rop-2.35
1 | GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.1) stable release version 2.35. |
1 | chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=71bdaa4e6af292c2f768dad63ba43949ee801dcb, for GNU/Linux 3.2.0, not stripped |
- 64位,dynamically,Partial RELRO,NX
漏洞分析
简单栈溢出:
1 | system("echo Enter something:"); |
入侵思路
先起一个 docker,执行如下命令拷贝 libc 文件:
1 | docker cp 61a471ee750d:/lib/x86_64-linux-gnu/libc.so.6 . |
先给出一个简单的脚本:
1 | system_maigc = 0x401169 |
唯一一个需要解决的问题就是 system 报错:
1 | ► 0x7ffff7de3963 movaps xmmword ptr [rsp], xmm1 |
- 该汇编指令的含义为:从 xmm1 拷贝16字节的数据到 RSP
- movaps xmmword 会检查栈是否对齐
解决完这个段错误后,system 还有可能不会执行,这是由于 RSP 上的地址最终指向了非“0”区域
1 | *RSP 0x7fffffffdc80 —▸ 0x403e00 ◂— 0x0 /* 合法 */ |
- 可以通过调整
gadget ret
的数目来调整 RSP 使其满足条件
另外写入的 ret
也不能过多,否则会破坏其后的关键数据(环境变量等)
完整 exp 如下:
1 | # -*- coding:utf-8 -*- |
selfcet
1 | GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.1) stable release version 2.35. |
1 | xor: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=6351f884825de925635334fd77a7aa091b2a8de2, for GNU/Linux 3.2.0, not stripped |
- 64位,dynamically,Full RELRO,Canary,NX
漏洞分析
栈溢出漏洞:
1 | read_member(&cxt, 0LL, 0x58uLL); |
可以覆盖函数指针:
1 | if ( cxt->status ) |
入侵思路
位于 cxt->func
的函数指针可以被覆盖,但对覆盖后的地址有一定的检查,经过查找只有以下4处地址符合条件:
1 | pwndbg> search -t dword 0xFA1E0FF3 |
还有一种方法就是将 err 覆盖低位变为其他 libc function,其中最好的目标就是 puts:(爆破概率为 1/4096)
1 | pwndbg> telescope 0x7ffff7e13ed0 |
但如果最后要打 system 会遇到莫名其妙的错误:
1 | ► 0x7ffff7e7e0f0 <execve> endbr64 |
- 返回值为 0xfffffffffffffff2,表示一个未定义的错误
- 猜测大概率是环境变量的问题
想要解决这个问题就要直接执行 execve,并将环境变量设置为 “0”,但由于程序使用 edi 导致 libc 中的 /bin/sh
地址不能写入:
1 | .text:00000000004011A8 89 C7 mov edi, eax |
因此这里先选择用 libc_start_main
重新执行程序,然后通过 gets 往可控地址中写入 /bin/sh
,最后执行一个 execve 就可以了
完整 exp 如下:
1 | # -*- coding:utf-8 -*- |
DataStore1
1 | GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.1) stable release version 2.35. |
1 | chall: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f7db7c5af40bd044bf0bc48be35bc65a1d1a08a0, for GNU/Linux 3.2.0, not stripped |
- 64位,dynamically,全开
程序分析
本题目给了源码:
- create 模块会要求输入 Type 以表示数据的类型
- edit 模块会根据不同的 Type 来调用不同的函数
程序中有一句 scanf("%70m[^\n]%*c", &buf)
,它的基础逻辑就是读取最多70字节到 buf,但在内存中程序会先申请 0x70 大小的 chunk,然后调用 realloc 将其调整为合适大小的 chunk:
1 | Allocated chunk | PREV_INUSE |
1 | Free chunk (tcache) | PREV_INUSE |
漏洞分析
有 UAF 漏洞:
1 | static int remove_recursive(data_t *data){ |
堆溢出漏洞:
1 | unsigned idx = getint(); |
入侵思路
核心思路就是利用堆溢出来修改相邻下一个 chunk 的数据:
1 | add("a",0x6) |
- 如果数据类型为 array,则程序会在 chunk 的第一片8字节空间中写入该 array 的大小
- 利用堆溢出可以修改 array->size,从而引发更大范围的堆溢出
下面是泄露堆地址的样例:
1 | add("a",0x6) |
- 通过堆溢出扩大 array0->size,从而使其可以访问到 string1->data
- 通过
arr_update2(0,6,"a",0x10)
申请 array1-6 实际上溢出到了 string1->data 的区域,并往 string1->data 中写入了一个堆地址
现在可以通过修改 string1->data 来间接修改 array1-6,接着我们需要释放大量 chunk 以得到 unsorted chunk,并伪造好 array1-6 的结构,再次打印时就可以泄露 libc_base 了:
1 | for i in range(10): |
完成泄露以后,我们可以劫持 libc GOT,在 realloc@got[plt]
中写入 system
即可
完整 exp 如下:
1 | # -*- coding:utf-8 -*- |
blackout
1 | GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.3) stable release version 2.35. |
1 | blackout: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4c3a010b465f17f8212ac92f19b5b63be856f16b, for GNU/Linux 3.2.0, not stripped |
- 64位,dynamically,Full RELRO,Canary,NX
漏洞分析
程序有一个强转,导致 find 只能接受到后4字节:
1 | for ( chunk = chunk_list[index]; max > chunk - chunk_list[index]; chunk = &next[len] ) |
入侵思路
这个题目脑洞有点大:
- 程序会截断 memmem 返回的地址,但程序没有开 PIE 导致申请到的 chunk 地址都在32位的范围内
- 我们的目标就是反复执行 malloc,以保证之后的 chunk 在32位的范围外
之后就可以通过截断后的 memmem 来修改 chunk_list 地址上的内容:
1 | pwndbg> telescope 0x404060 |
- 覆盖 0x14a0600 末尾的 “\x00” 就可以泄露 heap_base
泄露 heap_base 和 libc_base 的脚本如下:
1 | add(0, 0x10) |
接下来需要劫持 tcache head,将其中的某个 tcache bin 的倒数第2字节改为 0x2a
(为了 chunk 地址合法,不能该最后一字节)
由于开了 PIE,我们需要根据泄露的 heap_base 来定制 payload,并在 fake tcache bin 中伪造 fake chunk,因此还需要先泄露 tcache key
接着就可以劫持 tcache head 进而劫持 0x404060,然后通过 __libc_argv
泄露栈地址:
1 | dele(6) |
最后劫持栈就可以了
完整 exp 如下:
1 | # -*- coding:utf-8 -*- |