专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
终码一生  ·  用好缓存的10条军规 ·  13 小时前  
终码一生  ·  用好缓存的10条军规 ·  13 小时前  
文明内蒙古  ·  严正声明! ·  昨天  
文明内蒙古  ·  严正声明! ·  昨天  
福建市场监管  ·  10多秒飙到400℃!不少人随身携带,赶紧自查 ·  昨天  
福建市场监管  ·  10多秒飙到400℃!不少人随身携带,赶紧自查 ·  昨天  
51好读  ›  专栏  ›  看雪学苑

长城杯2025 (php-pwn) simi-final php-master 详解

看雪学苑  · 公众号  · 互联网安全  · 2025-05-24 17:59

正文

请到「今天看啥」查看全文




在解析具体函数之前介绍一下

0)zend_parse_parameters函数   (GPT写的)

???? 函数原型


ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...);


参数说明:


参数
说明
num_args
PHP 调用时实际传入参数的数量,一般用 ZEND_NUM_ARGS()
type_spec
参数类型字符串,例如 "ll" 表示两个 long 类型
...
用于接收解析结果的变量的地址(按顺序传入)


常见类型字符


字符
含义
C 变量类型
l
long / int(整型)
zend_long
d
double(浮点型)
double
s
字符串(和长度)
char *
, size_t
b
bool
zend_bool
z
zval *(通用)
zval *
a
数组
zval *
o
对象
zval *
`
`
可选参数的分隔符


1)zif_construct函数


还原结构体,大致如下




2)zif_allocate函数


3)zif_overwrite函数


同时汇编观察发现,zend_parse_parameters 函数的传入参数其实很多,修正一下。



这下对劲了。。


4)zif_clear函数


基本的需要利用的漏洞函数都已解析完毕。


注意到,本质是堆的UAF 任意地址写,同时overwrite函数没有检查init。


7. php源码 -> emalloc 和 efree 以及堆  大致粗略分析

从题目的docker容器中可以查找到对应的php版本


php --version
PHP 8.1.20 (cli) (built: Jun 13 2023 12:02:18) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.20, Copyright (c) Zend Technologies


下载它的源码

heap相关结构体

_zend_mm_heap


struct_zend_mm_heap {
#if ZEND_MM_CUSTOM
    int                use_custom_heap;
#endif
#if ZEND_MM_STORAGE
    zend_mm_storage   *storage;
#endif
#if ZEND_MM_STAT
    size_t             size;                    /* current memory usage */
    size_t             peak;                    /* peak memory usage */
#endif
    zend_mm_free_slot *free_slot[ZEND_MM_BINS]; /* free lists for small sizes */
#if ZEND_MM_STAT || ZEND_MM_LIMIT
    size_t             real_size;               /* current size of allocated pages */
#endif
#if ZEND_MM_STAT
    size_t             real_peak;               /* peak size of allocated pages */
#endif
#if ZEND_MM_LIMIT
    size_t             limit;                   /* memory limit */
    int                overflow;                /* memory overflow flag */
#endif

    zend_mm_huge_list *huge_list;               /* list of huge allocated blocks */

    zend_mm_chunk     *main_chunk;
    zend_mm_chunk     *cached_chunks; /* list of unused chunks */
    int                chunks_count; /* number of allocated chunks */
    int                peak_chunks_count; /* peak number of allocated chunks for current request */
    int                cached_chunks_count; /* number of cached chunks */
    double             avg_chunks_count; /* average number of chunks allocated per request */
    int                last_chunks_delete_boundary; /* number of chunks after last deletion */
    int                last_chunks_delete_count;    /* number of deletion over the last boundary */
#if ZEND_MM_CUSTOM
union {
struct {
            void      *(*_malloc)(size_t);
void       (*_free)(void*);
            void      *(*_realloc)(void*, size_t);
        } std;
struct {
            void      *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
void       (*_free)(void*  ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
            void      *(*_realloc)(void*, size_t  ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
        } debug;
    } custom_heap;
    HashTable *tracked_allocs;
#endif
};


_zend_mm_chunk


struct_zend_mm_chunk {
    zend_mm_heap      *heap;
    zend_mm_chunk     *next;
    zend_mm_chunk     *prev;
    uint32_t           free_pages; /* number of free pages */
    uint32_t           free_tail;               /* number of free pages at the end of chunk */
    uint32_t           num;
    char               reserve[64 - (sizeof(void*) * 3 + sizeof(uint32_t) * 3)];
    zend_mm_heap       heap_slot;               /* used only in main chunk */
    zend_mm_page_map   free_map;                /* 512 bits or 64 bytes */
    zend_mm_page_info  map[ZEND_MM_PAGES];      /* 2 KB = 512 * 4 */
};


注释写的还算比较好理解


emalloc


ZEND_API void* ZEND_FASTCALL _emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)






请到「今天看啥」查看全文