首页 > 编程语言 >ctf中常见php漏洞

ctf中常见php漏洞

时间:2023-10-29 18:00:55浏览次数:27  
标签:数字 00% 漏洞 ctf 数组 字符串 绕过 php md5

PHP特性漏洞

一.intval()函数---获取变量的整数值

函数说明

int intval (mixed $var [, int $base = 10 ] ) :通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

如果base是0,则通过检测var的格式来决定使用的进制:

  1. 如果字符串包括'0x'或者('0X')的前缀,使用16进制(hex);
  2. 如果字符串以 "0" 开始,使用 8 进制(octal);
  3. 否则,使用10进制(decimal).

返回值 : 成功时返回var的integer值,失败时返回0。空的array返回0,非空的array返回1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval('1000000000000') 会返回2147483647。64 位系统上,最大带符号的 integer 值是9223372036854775807

绕过思路总结

  1. 当某个数字被过滤时,可以使用它的 8进制/16进制来绕过;比如过滤10,就用012(八进制)或0xA(十六进制)。

  2. 对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。

  3. 当某个数字被过滤时,可以给它增加小数位来绕过;比如过滤3,就用3.1(转换小数类型时,只返回个位数,不遵循四舍五入的原则)

  4. 当某个数字被过滤时,可以给它拼接字符串来绕过;比如过滤3,就用3ab。(GET请求的参数会自动拼接单引号)

  5. 当某个数字被过滤时,可以两次取反来绕过;比如过滤10,就用~~10。

  6. 当某个数字被过滤时,可以使用算数运算符绕过;比如过滤10,就用 5+5 或 2*5。

  7. 科学计数法:经过本地测试,在php版本小于等于7.0.9时,intval("1e2")的结果是1,即转换字符串时,遇到字母停止,但是intval("1e2"+1)的结果却是101,这种特性可以绕过诸如intval($num)>2020&&intval($num)>2021。但是当php版本>7.0.9时,这种方法就失效了,因为intval("1e2")和intval(1e2)的值均为100。

二.is_numeric()函数---获取变检测变量是否为数字或数字字符串

函数说明

如果var是数字或数字字符串则返回 TRUE,否则返回 FALSE

绕过思路总结

1.加字母绕过

 if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
      $flag4 = True;
    }else{
      die("nope,this is level 4");
    }

这时,就可以通过传入key5=2024a(不是纯数字字符串)绕过(一个大于2023的数字加上任意字母)

2.16进制绕过

image-20231029141635633

php版本大于等于7.0.9时:当我们传入0x2时,会自动加上引号,在本地测试时,var_dump(is_numeric('0x1'));会返回bool(false),而var_dump(is_numeric(0x1));则会返回bool(true)。

但是当php版本小于7时,则可以利用,例如:

<?php
highlight_file(__FILE__);
$a = $_GET['a'];
if(is_numeric($a)){
    echo 'flag';
}
?>

传入a=0x1可以绕过,如图:

image-20231029143941820

3.科学计数法(is_numeric()配合()int强制类型转换绕过)

例如:

<?php
show_source(__FILE__);
$flag = "xxxx";
if(isset($_GET['time'])){ 
        if(!is_numeric($_GET['time'])){ 
                echo 'The time must be number.'; 
        }else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){ 
                        echo 'This time is too short.'; 
        }else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){ 
                        echo 'This time is too long.'; 
        }else{ 
                sleep((int)$_GET['time']); 
                echo $flag; 
        } 
                echo '<hr>'; 
}
?>

有题目可知:5184000<time<7776000,此时,可以利用:int(),不能正确转换的类型有十六进制型字符串、科学计数法型字符串;而
is_numeric()支持普通数字型字符串、科学记数法型字符串、部分支持十六进制0x型字符串。构造payload如下:

time=7e6

小tips:一开始写成了648e4,发现不行,因为要注意科学计数法前面那个数字必须是0~10(不包括10)之间的数字!

三.strcmp()函数---比较字符串大小(php -v<5.3)

函数说明

int strcmp ( string $str1 , string $str2 )

返回值:如果 str1 小于str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。

绕过思路总结

1.弱类型比较

<?php
 error_reporting(0);
 //关闭错误提示
if (isset($_GET['a'])) {  
    //判断是否以get形式为a赋值
    if (strcmp($_GET['a'], $flag) == 0) 
        //比较a变量和flag的字符,再将结果与0【false】比较
        echo 'flag{strcmp_pass}'; 
    else  
        print 'you are failure';  
}
?>

由于strcmp只会处理字符串,如果给个数组的话呢,就会返回NULL。而NULL==0,则可以成功得到flag。

四.hash比较缺陷---md5,sha1

一.md5弱类型比较(md5($a)==md5($b))

1.数组绕过:由于md5不能加密数组,在加密数组的时候会返回NULL,所以我们可以传入两个数组。数组绕过适用于源码中没有判断类型和内容,如果题目中加入了过滤函数,便不能使用了。

2.科学计数法绕过:可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是$\color{#FF3030}{纯数字}$,这样php在进行科学计算法的时候才会将它转化为0。可以自己写脚本:

import hashlib

for i in range(1,10**9):
    i=str(i)
    md=hashlib.md5(i.encode()).hexdigest()
    if(md[:2]=="0e" and md[2:].isdigit()):
        print("num={},md5={}".format(i,md))

要注意的是,int型没有encode属性,所以务必加上i=str(i)。其次,该脚本只能跑出数字型的答案,字符串的暂时无法跑出。

常见字符串如下:

纯数字类:

240610708 0e462097431906509019562988736854

314282422 0e990995504821699494520356953734

571579406 0e972379832854295224118025748221

903251147 0e174510503823932942361353209384

1110242161 0e435874558488625891324861198103

1320830526 0e912095958985483346995414060832

1586264293 0e622743671155995737639662718498

2302756269 0e250566888497473798724426794462

2427435592 0e067696952328669732475498472343

2653531602 0e877487522341544758028810610885

3293867441 0e471001201303602543921144570260

3295421201 0e703870333002232681239618856220

3465814713 0e258631645650999664521705537122

3524854780 0e507419062489887827087815735195

3908336290 0e807624498959190415881248245271

4011627063 0e485805687034439905938362701775

4775635065 0e998212089946640967599450361168

4790555361 0e643442214660994430134492464512

5432453531 0e512318699085881630861890526097

5579679820 0e877622011730221803461740184915

5585393579 0e664357355382305805992765337023

6376552501 0e165886706997482187870215578015

7124129977 0e500007361044747804682122060876

7197546197 0e915188576072469101457315675502

7656486157 0e451569119711843337267091732412

大写字母类:

QLTHNDT 0e405967825401955372549139051580

QNKCDZO 0e830400451993494058024219903391

EEIZDOI 0e782601363539291779881938479162

TUFEPMC 0e839407194569345277863905212547

UTIPEZQ 0e382098788231234954670291303879

UYXFLOI 0e552539585246568817348686838809

IHKFRNS 0e256160682445802696926137988570

PJNPDWY 0e291529052894702774557631701704

ABJIHVY 0e755264355178451322893275696586

DQWRASX 0e742373665639232907775599582643

DYAXWCA 0e424759758842488633464374063001

GEGHBXL 0e248776895502908863709684713578

GGHMVOE 0e362766013028313274586933780773

GZECLQZ 0e537612333747236407713628225676

NWWKITQ 0e763082070976038347657360817689

NOOPCJF 0e818888003657176127862245791911

MAUXXQC 0e478478466848439040434801845361

MMHUWUV 0e701732711630150438129209816536

byGcY

0e591948146966052067035298880982

QNKCDZO

0e830400451993494058024219903391

s878926199a

0e545993274517709034328855841020

s155964671a

0e342768416822451524974117254469

s214587387a

0e848240448830537924465865611904

s214587387a

0e848240448830537924465865611904

s878926199a

0e545993274517709034328855841020

s1091221200a

0e940624217856561557816327384675

s1885207154a

0e509367213418206700842008763514

3.MD5和双MD5以后都是0e开头的:(但是后面不是$\color{#FF3030}{纯数字}$,不太好用)

CbDLytmyGm2xQyaLNhWn

770hQgrBOjrcqftrlaZk

7r4lGXCH2Ksu2JNT3BYM

4.一个数自己和MD5值均以0e开头:

num=0e215962017,md5=0e291242476940776845150308577824 脚本如下:

import hashlib

for i in range(1,10**40):
    i='0e'+str(i)
    md=hashlib.md5(i.encode()).hexdigest()
    if md[:2]=="0e" and md[2:].isdigit():
        print('num={},md5={}'.format(i,md))
        break

其中,第5行还可以写成md=hashlib.new('md5',i.encode()).hexdigest();之所以要编码,是因为ython3默认编码是unicode,而不是字节码bytes。hash是要基于bytes的,因此需要encode()函数编码。因为需要进行下标访问,而刚才的返回值又是hash类型,所以应该使用函数将md变成一个字符串。一开始的时候,我还在想为什么只能用hexdigest()函数使其成为16进制字符串呢,后来再一看,哦,原来是需要出现"0e",那必然不能用digest()函数变成2进制了呀。当然了,又出现了一个小小的疑问,isdigit()和isnumeric(),isdecimal()的区别是什么呢?查资料发现:

isdecimal:是否为十进制数字符,包括Unicode数字、双字节全角数字,不包括罗马数字、汉字数字、小数;

isdigit:是否为数字字符,包括Unicode数字,单字节数字,双字节全角数字,不包括汉字数字,罗马数字、小数

isnumeric:是否所有字符均为数值字符,包括Unicode数字、双字节全角数字、罗马数字、汉字数字,不包括小数。

二.md5强类型比较(md5($a)===md5($b))

方法一:数组绕过

因为是强类型比较,用0e开头的字符串是没办法绕过的了,但是PHP自身的特性使得可以提交一个数组而md5函数传入数组的返回值都是NULL,这样就可以绕过强类型比较了。

方法二:MD5强碰撞绕过

具体原理很复杂,但是实现方法不难,是通过fastcoll_v1.0.0.5.exe.zip这个工具,创造两个txt文件,然后进行二进制md5加密,可以获得两个数值和类型都相等的字符串。由于加密后存在不可见字符,因此需要进行URL编码,下面给出两组碰撞结果:

p1=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8EF%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28%FAU%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9b4%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%9DFH%F1%25%AC%DF%FA%C4G%27uW%CFNB%E7%EF%B0
p2=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8E%C6%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28zV%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9%E24%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D%B7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%1DFH%F1%25%AC%DF%FA%C4G%27uW%CF%CEB%E7%EF%B0
p1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
p2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

五.json绕过

先了解一下什么是JSON:

JSON: JavaScript Object Notation(JavaScript 对象表示法)

JSON 是存储和交换文本信息的语法,类似 XML。

JSON 比 XML 更小、更快,更易解析。

JSON 易于人阅读和编写。

C、Python、C++、Java、PHP、Go等编程语言都支持 JSON。

JSON语法:JSON 语法是 JavaScript 对象表示语法的子集。

  • 数据在名称/值对中
  • 数据由逗号 , 分隔
  • 使用斜杆 ** 来转义字符
  • 大括号 {} 保存对象
  • 中括号 [] 保存数组,数组可以包含多个对象
<?php
if (isset($_POST['message'])) {
    $message = json_decode($_POST['message']);
    $key ="*********";
    if ($message->key == $key) {
        echo "flag";
    } 
    else {
        echo "fail";
    }
 }
 else{
     echo "~~~~";
 }
?>

输入一个json类型的字符串,json_decode函数解成一个数组,判断数组中key的值是否等于 $key的值,但是$key的值我们不知道,但是可以利用0==”admin”这种形式绕过.

payload:

message={"key":0}

六.parse_str()变量覆盖

函数说明

parse_str — 将字符串解析成多个变量:void parse_str ( string $encoded_string [, array &$result ] )

解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量,当parse_str()函数的参数值可以被用户控制时,则存在变量覆盖漏洞。

<?php
error_reporting(0);
if(empty($_GET['id'])) {
  show_source(__FILE__);
  die();
} else {
  $a = "www.xxx.com";
  $id = $_GET['id'];
  @parse_str($id);
  if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
    echo 'flag';
  } else {
    exit('so easy!');
  }
}
?>

由上述描述,易得payload:

?id=a[0]=s878926199a                 (s878926199a被md5加密后,以0e开头)

七.extract()函数

extract()函数从数组中将变量到导入到当前符号表
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表创建对应的一个变量
<?php
error_reporting(0);
echo "同目录下有个test.txt,猜猜里面写了什么,猜对了奖励你flag哦~<br>";
$text='test.txt';
extract($_GET);
 if(isset($a)){
    $content=trim(file_get_contents($text));
    if($a==$content){
        echo "<br>骗你的,根本没有test.txt哈哈<br>flag{Y0u_G0t_1t!}";
    }
    else{
        echo "Not like that, think again";
    }
 }

由于我们并不知道test.txt的内容,因此我们只需要利用extract函数将$text的值覆盖为空,再把$a赋值为空即可即可

八.in_array()函数

用途:用来判断一个值是否在某一个数组列表里面

缺陷:存在自动类型转换 ,当输入数字1后再紧跟其他字符串能够Bypass检测数组的功能

例题:

<?php
$id = $_GET['id'];
if (in_array($id, array(1,2,3,4,5,6,7,8,9,0))) {
  $sql = "Select a From users Where Id='".$id."'";
  echo $sql;
} else {
  echo "No...";
}
?>
payload:1' union select * from users#

image-20231029170653524

九.ereg()函数和eregi()函数(php4,php5)

用于正则匹配,两者的区别在于是否区分大小写 使用指定的模式搜索一个字符串中指定的字符串,如果匹配成功则返回true,否则返回false

该函数可被%00截断来Bypass 传入数组之后,ereg是返回NULL

<?php
$passwd = $_GET['passwd'];
if (@ereg("^[a-zA-Z0-9_]+$", $passwd)) {
  $sql = "Select username From users Where password='".$passwd."'";
  echo $sql;
} else {
  echo "No...";
}
?>

image-20231029171105770

十.$$导致变量覆盖

$$导致变量覆盖的问题一般出现在foreach遍历数组当中,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量名,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。

<?php
error_reporting(0);
$name='Testing';
foreach ($_GET as $key => $value)
    $$key = $value;
var_dump($key);
var_dump($value);
var_dump($$key);
echo $name;

image-20231029171904688

此时,当我们传入name=dtwin时,$name的值被覆盖为dtwin

总结

以上十个漏洞是php中较为常见的,另外的漏洞比如import_request_variables()变量覆盖,register_globals全局变量覆盖,这些都在php5以后就废除了,ctf和实战中都很难再遇到,故不在此列出。

标签:数字,00%,漏洞,ctf,数组,字符串,绕过,php,md5
From: https://www.cnblogs.com/dtwin/p/17796132.html

相关文章

  • CTFshow Reverse 数学不及格 wp
    1.elf文件使用IDA反汇编main函数,主要逻辑写在注释里,要算出除程序名之外的4个参数2.根据伪代码分析数据前三个check相加,有(v9-v10)+(v9-v11)+(v9-v12)=3*v9-(v10+v11+v12)=0x233F0E151C+0x1B45F81A32+0x244C071725=0x62d10d4673而check4v4+v10+v11+v12=0x13A31412F8C两个等......
  • java基础漏洞学习----整数溢出漏洞+硬编码漏洞+不安全的随机数生成器
    java基础漏洞学习----整数溢出漏洞+硬编码漏洞+不安全的随机数生成器整数溢出漏洞publicclassNumberLearning{publicstaticvoidmain(String[]args){System.out.println(Integer.MAX_VALUE+1);System.out.println(Integer.MIN_VALUE-1);}}......
  • java基础漏洞学习----SSRF漏洞
    java基础漏洞学习----SSRF漏洞JAVA的SSRF常见利用协议仅支持sun.net.www.protocol下所有的协议:http,https,file,ftp,mailto,jar及netdoc传入的URL必须和重定向后的URL协议一致,JAVA中的SSRF不能和PHP中一样使用gother协议来扩展攻击面常见的可以发起网络请求,并且会导致SSRF......
  • 【pwn】[SWPUCTF 2021 新生赛]nc签到 --shell过滤字符
    附件下载打开:importosart='''  (( "####@@!!$$  ))    `#####@@!$$` ))  (( '####@!!$:  (( ,####@!!$: ))    .###@!!$:    `##@@!$:    `#@!!$ !@#  `#@!$:   @#$  #$  `#@!$:   !@!......
  • 用友反序列化漏洞综合
    用友NC序列化漏洞综合利用工具分享下载地址https://github.com/wgpsec/YongYouNcTooljava11以上的环境可使用集成了以下漏洞BshServletrcejsInvokerceDeleteServletcc6反序列化DownloadServletcc6反序列化FileReceiveServletcc6反序列化fsDownloadServletc......
  • 用友NC accept.jsp任意文件上传漏洞
    漏洞简介用友NCaccept.jsp处存在任意文件上传漏洞,攻击者通过漏洞可以获取网站权限,导致服务器失陷。漏洞复现fofa语法:app="用友-UFIDA-NC"登录页面如下:POCPOST/aim/equipmap/accept.jspHTTP/1.1Host:106.14.160.167:8090User-Agent:Mozilla/5.0(WindowsNT6.4;WOW......
  • CTFshow Reverse 红包题 武穆遗书 wp
    1.查看文件信息,是32位exe文件有upx壳2.脱壳后使用32位IDA打开,分析伪代码有反调试,但是check很简单,直接比较输入和变换后的内容3.通过attach来过反调试如下图设置断点,运行exe后先不输入,ida的Debugger->Attachtoprocess,选择正在等待输入的exeattach后,在exe黑窗中任意输入,......
  • php-SER-libs-main反序列化靶场部分wp
    什么是序列化/反序列化,为什么要进行序列化/反序列化序列化:有时需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化)。反序列化:将序列化的结果还原PHP序列化:把对象转化为二进制的字符......
  • ctf_show Web的Web8题解
    好久没写博客,上次写还是在上次(三年前)。如题,写一次CTF的题解 根据题目提示得知这应该是一个注入,什么注入还不知道,进入靶场。 仅有三个地方可点,都点进去看看。从URL处可以看到前端是传了一个参数id给后端(另外两个类似,就不贴图了)。那很明显了是SQL注入。 首先在参数后......
  • 2023寒鹭Tron-CTF迎新赛 CRYPTO Misc 全WP
    CRYPTO简简单单1、题目信息U2FsdGVkX1+2gTXPuTetdM1p+IETUDXAHe2eC33jQfgdJoOmmrJq2、解题方法兔子密码,在线工具直接解简简单单21、题目信息part1offlag:++++++++++[->++++++++++<]>++.++++++.<+++[->---<]>--.++++++.<++++[->++++<]>++++.-----......