其他小技巧

roko / 2024-08-07 / 原文

🚩哈希长度扩展攻击

  • 原理:由于hash的生成机制,使得我们可以人为的在原先明文数据的基础上添加新的拓展字符,使得原本的加密链变长,进而控制加密链的最后一届,使得我们控制最终的结果

  • 一个简单的例子

    <?php
    include "flag.php";
    $secretKey = 'xxxxxx'; #xxx为未知内容,但长度已知为6。
    $v1 = $_GET['str'];
    $sign = $_GET['sign'];
    $token = md5($secretKey.$v1);
    if($v1 === 'test') {
        die($token); #token=2df51a84abc64a28740d6d2ae8cd7b16
    } else {
        if($token === $sign) {
            die($flag);
        }
    }
    ?>
    

    我们发现只有当token=sign的值时,才能获得flag,但是token是通过md5($secretKey.$v1)生成的,但是我们不知道secrectkey的值,所以这时候就要想到hash长度扩展攻击

  • 工具:hashpump

🚩url中的unicode漏洞引发的域名安全问题

  • 一些编码:

    • unicode:Unicode涵盖的数据除了视觉上的字形、编码方法、标准的字符编码外,还包含了字符特性,如大小写字母
    • ascii编码:一共定义了128个编码
    • idna:应用程序国际化域名,是一种以标准方式处理ascii以外字符的一种机制,从unicode中提取字符,并允许非ASCII码字符以允许使用的ASCII字符表示
  • 漏洞分析:

    域名欺骗(http://Вaidu.com->http://вaidu.com):当我们访问http://Вaidu.com时,浏览器会将我们访问的url交给域名系统DNS解析为ip地址,在解析url时采取递归查询和迭代查询,就是先递归搜索浏览器自己的dns缓存,然后搜索操作系统的dns缓存,接着搜索hosts文件缓存,搜索本地域名服务器等,直到搜索到ip地址为止,而在dns中,idna使用Punycode转写并以ascii字符串储存。在本地dns中,因为遇见特殊字符B,而无法将此url正常转化为ascii,因此就在本地转化为http://xn--aidu-f4d.com/这种形式的url

  • idna转写为ascii的过程

    • 正常化,将字符转化为ascii码的形式
    • 用punycode编码将unicode编码成ascii码
  • 域名分割

    在unicode中还有一种字符℀,当idna处理这个字符时,℀就会变为a/c当我们访问带有这个字符的网站时,dns就会自动将url重定向到另一个网站,如果服务器引用前端url时,只对域名做了限制,那么通过这种方法就可以绕过对域名的限制了

    https://xz.aliyun.com/t/6070?time__1311=n4%2BxnD0DgDcmG%3DrDsYoxCqiKnZ2ieDBlDQuppD

  • 示例题目

    @app.route('/getUrl', methods=['GET', 'POST'])
    def getUrl():
        url = request.args.get("url")
        host = parse.urlparse(url).hostname#提取url中的主机名
        if host == 'suctf.cc':
            return "我扌 your problem? 111"
        parts = list(urlsplit(url))
        host = parts[1]
        if host == 'suctf.cc':
            return "我扌 your problem? 222 " + host
        newhost = []
        for h in host.split('.'):#对于主机名,通过循环将其每个部分进行编码和解码处理,并重新组合
            newhost.append(h.encode('idna').decode('utf-8'))
        parts[1] = '.'.join(newhost)
        #去掉 url 中的空格
        finalUrl = urlunsplit(parts).split(' ')[0]
        host = parse.urlparse(finalUrl).hostname
        if host == 'suctf.cc':#如果新的主机名还是suctf.cc,使用urllib.request.urlopen(finalUrl).read()读取url的内容
            return urllib.request.urlopen(finalUrl).read()
        else:
            return "我扌 your problem? 333"
        #这道题的意思就是前两次处理不能含有suctf.cc,但是第三次必须有
    

    分析一下具体的意思就是,经过两次过滤之后,传入的字符串要有suctf.cc,但是前两次会将suctf.cc过滤掉,所以我们就考虑使用unicode漏洞引发的域名安全问题

🚩系统命令调用

  • putenv('PATH=/home/rceservice/jail');意味着我们无法直接调用cat指令,因为这些指令实际存放在特定目录中封装好的程序,path环境变量就是存放这些特定目录的路径方便我们去调用这些指令,而这道题限制了路径,那么我们只能调用绝对路径来调用指令

🚩linux的proc目录使用

  • proc目录:在linux系统上的/proc目录是一种文件系统,即proc文件系统。与其他常见的文件系统不同的是,/proc是一种伪文件系统也就是虚拟文件系统,存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改改变内核的运行状态
  • 简单来讲,/proc目录即保存在系统内存中的信息,大多数虚拟文件可以使用文件查看命令如cat、more或者less进行查看,有些文件信息表述的内容可以一目了然,但也有文件的信息却不怎么具有可读性
  • 相关的进程文件
    • cmdline:cmdline 文件存储着启动当前进程的完整命令,但僵尸进程目录中的此文件不包含任何信息。可以通过查看cmdline目录获取启动指定进程的完整命令
    • cwd:cwd 文件是一个指向当前进程运行目录的符号链接。可以通过查看cwd文件获取目标指定进程环境的运行目录
    • exe:exe 是一个指向启动当前进程的可执行文件(完整路径)的符号链接。通过exe文件我们可以获得指定进程的可执行文件的完整路径
    • environ(可以获取环境变量中的flag):environ 文件存储着当前进程的环境变量列表,彼此间用空字符(NULL)隔开。变量用大写字母表示,其值用小写字母表示。可以通过查看environ目录来获取指定进程的环境变量信息
    • fd:fd 是一个目录,里面包含这当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接,即每个通过这个进程打开的文件都会显示在这里。所以我们可以通过fd目录里的文件获得指定进程打开的每个文件的路径以及文件内容(在 linux 系统中,如果一个程序用open()打开了一个文件但最终没有关闭他,即便从外部(如os.remove(SECRET_FILE))删除这个文件之后,在 /proc 这个进程的 pid 目录下的 fd 文件描述符目录下还是会有这个文件的文件描述符,通过这个文件描述符我们即可得到被删除文件的内容)
    • self:获取当前进程的信息
      • 获取目标当前进程环境的运行目录与目录里的文件:ls /proc/self/cwd
      • 获得当前进程的可执行文件的完整路径:ls -al /proc/self/exe
      • 获取当前进程的环境变量信息:cat /proc/self/environ