Aegis招新WriteUp
Adventures in PHP (0)
很明显,flag 就在 flag1.php
的 $flag
变量中。
观察发现 $flag
变量必须存在且非 NULL
,而且用到了 strcmp()
字符串比较函数。而我输入的值显然不可能等于$flag
的值,故只能想办法绕过 strcmp()
函数来达到显示 flag 的目的。
查阅 PHP 官方手册中有关 strcmp()
函数的说明,发现当字符串和数组或一个对象进行比较时会得到 NULL
且返回警告:
所以最简单的办法,就是使用 GET
方法令变量 $flag
为一数组 flag[]=1
即可绕过 strcmp()
,成功得到 flag。
Adventures in PHP (1)
同样很容易看出,flag 就在 flag2.php
的某个变量中。
观察代码,发现需要以 GET
方法读入变量 $args
,且 $args
的值必须和正则表达式/^\w+$/
匹配,即匹配由数字、26 个英文字母或者下划线组成的字符串,这样才不会进入内层的 if
条件导致程序退出。
接下来是 eval(var_dump($$args););
。 eval()
可执行将字符串当成代码来执行,而 var_dump()
可以打印出变量的相关信息。又发现 $$args
是一个可变变量,即变量名为另一个变量,即 $args
。
由于不知道 flag 对应的变量名,所以无法直接传变量名得出 flag,再加上正则表达式的限定,于是联想到了传入超级全局变量数组 $GLOBALS
,即可让 var_dump()
打印出整个程序中所有变量的信息。
所以用 GET
方法传入 args=GLOBALS
即可得到对应 flag。
Is everything injectable?
1)
解法同上面第 2 题,用 GET
方法传入 args=GLOBALS
即可得到前半条 flag。
2)
尝试传入 hello=GLOBALS
发现 flag 不在全局变量中:
由于题目没有提供更多信息,故想到从被导入的那个 flag2.php
入手。借助 eval()
函数,
构造字符串 "1);print_r(file("flag2.php"));//"
,则该行代码变成如下代码:
1 | eval("var_dump(1);print_r(file("flag2.php"));//);"); |
即打印整数 1
的信息,然后打印出 flag2.php
的信息。于是得到后半条 flag:
拼接可得 flag: aegis{92853051ab8944f7865cf3c2128b34}
。
Adventures in PHP (2)
读题知:首先需存在一个值为 begin
的变量 mode
,且读入的变量 a
和 b
满足 md5($a)==sha1($b)
。 查阅资料知,md5()
函数和 sha1()
函数在对数组进行加密时将返回 NULL
,而 NULL==NULL
返回 true
,即可绕过该条件。故传入a[]=1&b[]=1
。
接下来由内部 if
条件得出,需要使用 POST
方法传入一个关联数组变量 $token
,其中应当存在 "user"=>"user"
, "pass"=>"pass"
两个键。所以构造数组 array("user"=>"user","pass"=>"pass")
并序列化得到以下字符串:
1 | a:2:{s:4:"pass";s:4:"pass";s:4:"user";s:4:"user";} |
序列化函数 serialize()
可以将 PHP
中的变量转化为一个表示了变量值的字符串,有利于存储或传递 PHP
的值,同时不丢失其类型和结构。要将序列化的字符串转为原变量,可使用 unserialize()
函数。
最后还有最内层的两个 if
条件。很容易看出,此处需要传入一个名为 $flag
的 last_task
对象,且需要 URL 编码和序列化。条件 $flag->middle===$flag->left&&$flag->middle===$flag->right
里的三等号表示不仅等号两端的值要相同,而且类型也要相同。而又不知道变量 $fl4g
的值,所以无法令 $flag->left
和 $flag->right
的值都等于 $fl4g
。于是引用变量 $flag->middle
,令 $flag->left=&$flag->middle
, $flag->right=&$flag->middle
。构造出 $flag
对象:
1 |
|
打印出的结果为:
1 | O%3A9%3A%22last_task%22%3A3%3A%7Bs%3A4%3A%22left%22%3BN%3Bs%3A6%3A%22middle%22%3BR%3A2%3Bs%3A5%3A%22right%22%3BR%3A2%3B%7D |
综上所述,GET
方法传入的变量有:mode=begin&a[]=1&b[]=1
,
POST
方法传入的变量有:
token=a:2:{s:4:"pass";s:4:"pass";s:4:"user";s:4:"user";}&flag=O%3A9%3A%22last_task%22%3A3%3A%7Bs%3A4%3A%22left%22%3BN%3Bs%3A6%3A%22middle%22%3BR%3A2%3Bs%3A5%3A%22right%22%3BR%3A2%3B%7D
传入变量得到 flag:
Adventures in PHP (3)
首先在代码中有一个 Flag
对象,里面包含一个 $file
变量和一个 __tostring
魔术方法。该方法在当对象被看作字符串进行操作时会自动执行。而在后面有一个对 $password
变量进行反序列化的操作,故猜想 $password
变量是一个序列化后的 Flag
对象。
同时,对 $txt
变量,有一个 file_get_contents()
的函数操作,即以字符串打印出文件的具体内容。而这里显然不可能传入一个文件,故使用 php://input
伪协议,此时当传进去的参数作为文件名变量去打开文件时,可以将参数 php://
传进,同时以 POST
方式传进去的值作为文件内容,供 PHP
代码执行时当做文件内容读取。于是此时 POST
一个字符串 welcome to the aegis
即可。
接下来处理变量 $password
。观察 __tostring
方法,发现会打印出文件名为 $file
的文件内容,故尝试令 $password=>file
的值为 flag3.php
,发现没有成功。查阅资料得知此处可用伪协议 php://filter
,使用 php://filter/read=convert.base64-encode/resource=flag3.php
可以用 base64
加密的方式读出文件的内容。故令 $password->file='php://filter/read=convert.base64-encode/resource=flag3.php'
,可读出一串字符:
用 base64
解码得到 flag3.php
的文件内容:
1 |
|
flag:aegis{35d6d33467aae9a2e3dccb4b6b027878}
。
EzSqli
进行 SQL 注入,猜测后台对数据库的操作大致如下:
1 | select * from table where username= '用户名' and password = '密码'; |
于是用户名和密码均输入 admin' or '1'='1
构造出恒成立语句:
1 | select * from table where username= ' admin' or '1'='1' and password =' admin' or '1'='1'; |
随后得到 flag: