From 6947aded0ed4bd4e052f4acd32e26858ee0c77e5 Mon Sep 17 00:00:00 2001 From: Cool-Y <1072916769@qq.com> Date: Sun, 17 Mar 2019 18:53:20 +0800 Subject: [PATCH] Site updated: 2019-03-17 18:53:16 --- .../BIBA访问控制模型实现(python)/index.html | 875 ++++++ 2019/03/16/hello-world/index.html | 713 +++++ 2019/03/16/qq数据库的加密解密/index.html | 750 +++++ .../wwifi半双工侧信道攻击学习笔记/index.html | 906 ++++++ 2019/03/16/小米固件工具mkxqimage/index.html | 761 +++++ archives/2019/03/index.html | 731 +++++ archives/2019/index.html | 731 +++++ archives/index.html | 731 +++++ categories/index.html | 602 ++++ css/fonts/FontAwesome.otf | Bin 62856 -> 0 bytes css/fonts/fontawesome-webfont.eot | Bin 38205 -> 0 bytes css/fonts/fontawesome-webfont.svg | 414 --- css/fonts/fontawesome-webfont.ttf | Bin 80652 -> 0 bytes css/fonts/fontawesome-webfont.woff | Bin 44432 -> 0 bytes css/images/banner.jpg | Bin 224710 -> 0 bytes css/main.css | 2675 +++++++++++++++++ css/style.css | 1374 --------- fancybox/blank.gif | Bin 43 -> 0 bytes fancybox/fancybox_loading.gif | Bin 6567 -> 0 bytes fancybox/fancybox_loading@2x.gif | Bin 13984 -> 0 bytes fancybox/fancybox_overlay.png | Bin 1003 -> 0 bytes fancybox/fancybox_sprite.png | Bin 1362 -> 0 bytes fancybox/fancybox_sprite@2x.png | Bin 6553 -> 0 bytes fancybox/helpers/fancybox_buttons.png | Bin 1080 -> 0 bytes fancybox/helpers/jquery.fancybox-buttons.css | 97 - fancybox/helpers/jquery.fancybox-buttons.js | 122 - fancybox/helpers/jquery.fancybox-media.js | 199 -- fancybox/helpers/jquery.fancybox-thumbs.css | 55 - fancybox/helpers/jquery.fancybox-thumbs.js | 165 - fancybox/jquery.fancybox.css | 273 -- fancybox/jquery.fancybox.js | 2017 ------------- fancybox/jquery.fancybox.pack.js | 46 - index.html | 1410 +++++++++ js/script.js | 137 - tags/IOT/index.html | 571 ++++ tags/index.html | 602 ++++ tags/密码/index.html | 571 ++++ tags/模型实现/index.html | 571 ++++ tags/论文/index.html | 571 ++++ 39 files changed, 13771 insertions(+), 4899 deletions(-) delete mode 100644 css/fonts/FontAwesome.otf delete mode 100644 css/fonts/fontawesome-webfont.eot delete mode 100644 css/fonts/fontawesome-webfont.svg delete mode 100644 css/fonts/fontawesome-webfont.ttf delete mode 100644 css/fonts/fontawesome-webfont.woff delete mode 100644 css/images/banner.jpg delete mode 100644 css/style.css delete mode 100644 fancybox/blank.gif delete mode 100644 fancybox/fancybox_loading.gif delete mode 100644 fancybox/fancybox_loading@2x.gif delete mode 100644 fancybox/fancybox_overlay.png delete mode 100644 fancybox/fancybox_sprite.png delete mode 100644 fancybox/fancybox_sprite@2x.png delete mode 100644 fancybox/helpers/fancybox_buttons.png delete mode 100644 fancybox/helpers/jquery.fancybox-buttons.css delete mode 100644 fancybox/helpers/jquery.fancybox-buttons.js delete mode 100644 fancybox/helpers/jquery.fancybox-media.js delete mode 100644 fancybox/helpers/jquery.fancybox-thumbs.css delete mode 100644 fancybox/helpers/jquery.fancybox-thumbs.js delete mode 100644 fancybox/jquery.fancybox.css delete mode 100644 fancybox/jquery.fancybox.js delete mode 100644 fancybox/jquery.fancybox.pack.js delete mode 100644 js/script.js diff --git a/2019/03/16/BIBA访问控制模型实现(python)/index.html b/2019/03/16/BIBA访问控制模型实现(python)/index.html index e69de29b..dd4049ef 100644 --- a/2019/03/16/BIBA访问控制模型实现(python)/index.html +++ b/2019/03/16/BIBA访问控制模型实现(python)/index.html @@ -0,0 +1,875 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 利用python实现BIBA模型 | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

利用python实现BIBA模型

+ + + +
+ + + + + +
+ + + + + +

基于python语言的BIBA模型图形界面实现

一、实验目的:

    +
  1. 查阅资料,了解biba安全模型的相关知识
  2. +
  3. 通过编程实现基于biba模型的完整性访问控制,进一步掌握biba模型的规则
  4. +
  5. 使用python语言实现,熟练pyqt的图形界面设计方法
  6. +
+
+

二、实验环境:

    +
  • 操作系统:Windows10
  • +
  • 工具版本:python3.7,pyqt5
  • +
+
+

三、实验原理:

1. 什么是安全模型

    +
  • 系统的元素
    +

    具有行为能力的主体
    不具有行为能力的客体

    +
    +
  • +
  • 系统的操作行为
    +

    可以执行的命令:读、写、执行

    +
    +
  • +
  • 对系统行为的约束方式
    +

    对行为的控制策略

    +
    +
  • +
  • 模型从抽象层次规定了系统行为和约束行为的方式
  • +
  • 模型往往用状态来表示
    +

    系统行为所依赖的环境
    行为对系统产生的效果

    +
    +

    2. biba完整性模型:

      +
    • 完整性威胁问题
      +

      完整性的威胁就是一个子系统在初始时刻认为不正常的修改行为;
      来源:内部&外部;
      类型:直接&间接

      +
      +
    • +
    +
  • +
+ + + + + + + + + + + + + + + + + +
外部的直接外部的间接内部的直接内部的间接
外部系统恶意地篡改另一个系统的数据或程序一个外部系统插入恶意的子程序修改自己的代码修改自己的指针
+
    +
  • biba模型的完整性定义
    +

    完整性级别高的实体对完整性低的实体具有完全的支配性,反之如果一个实体对另一个实体具有完全的控制权,说明前者完整性级别更高,这里的实体既可以是主体也可以是客体。
    完整性级别和可信度有密切的关系,完整级别越高,意味着可信度越高。

    +
    +
  • +
  • biba模型的规则
  • +
+
    +
  • 对于写和执行操作,有如下规则:
    +

    写规则控制
    当且仅当主体S的完整性级别大于或等于客体O的完整性级别时,主体S可以写客体O,一般称之为上写
    执行操作控制
    当且仅当主体S2的完整性级别高于或等于S1,主体S1可以执行主体S2。

    +
    +
  • +
  • 关于读操作,有不同的控制策略:
    +

    低水标模型
    任意主体可以读任意完整性级别的客体,但是如果主体读完整性级别比自己低的客体时,主体的完整性级别将为客体完整性级别,否则,主体的完整性级别保持不变。
    环模型
    不管完整性级别如何,任何主体都可以读任何客体
    严格完整性模型
    这个模型对读操作是根据主客体的完整性级别严格控制的,即只有完整性级别低或相等的主体才可以读完整性级别高的客体,称为下读

    +
    +
  • +
+

一般都是指毕巴严格完整性模型,总结来说是上写、下读

+
+

四、实验内容:

1. 用户登录实现

核对用户输入的账户密码与存储的是否匹配

+

login

+
    +
  • 从用户输入框获取账户和密码
  • +
  • 检查输入信息是否合法(为空)
  • +
  • 从password.txt中获取,并保存在列表listFromLine中
  • +
  • 检查输入的账户是否存在
  • +
  • 若存在,检查对应的密码是否正确
  • +
  • 若正确,判断是管理员还是普通用户,并跳转相应的界面

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    def checkPass(self):
    nameIn = self.lineEdit.text()
    passwdIn = self.lineEdit_2.text()
    md5 = hashlib.md5()
    md5.update(passwdIn.encode("utf-8"))
    passwdIn = md5.hexdigest()
    if (nameIn == '') or (passwdIn == ''):
    QMessageBox.warning(self,
    "警告",
    "账号和密码不能为空",
    QMessageBox.Yes)
    self.lineEdit.setFocus()
    print(nameIn, passwdIn)
    fr = open('./etc/passwd.txt')
    arrayofLines = fr.readlines()
    numberofLines = len(arrayofLines)
    for line in arrayofLines:
    line = line.strip()
    listFromLine = line.split(':')
    name = listFromLine[0]
    if name == nameIn:
    numberofLines = -1
    passwd = listFromLine[1]
    if passwd == passwdIn:
    group = listFromLine[2]
    print("\n登录成功!\n")
    if name == 'root':
    print('root登录')
    rootUI.show()
    MainWindow.close()
    else:
    urName = nameIn
    mainUI.lineEdit.setText(urName)
    mainUI.lineEdit_2.setText(group)
    mainUI.show()
    MainWindow.close()
    else:
    QMessageBox.warning(self,
    "警告",
    "密码错误!",
    QMessageBox.Yes)
    self.lineEdit.setFocus()
    fr.close()
    return 0
    +
  • +
+
+

2. 管理员功能实现

管理员可以对用户进行增、删、查的操作

+

login

+

增加用户的实现

+
    +
  • 获取管理员输入的用户名、密码和用户等级
  • +
  • 将明文密码转换为md5值
  • +
  • 判断输入的账户是否已经存在以及是否为空
  • +
  • 如果没有问题,将其存入passwd.txt的末尾
  • +
+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def adduser(self):
print('开始添加')
name = self.lineEdit_4.text()
passwd = self.lineEdit_6.text()
md5 = hashlib.md5()
md5.update(passwd.encode("utf-8"))
passwd = md5.hexdigest()
group = self.comboBox.currentText()
self.name = name
if self.euxit():
if name == '' or passwd == '':
QMessageBox.warning(self,
"警告",
"账号和密码不能为空",
QMessageBox.Yes)
self.lineEdit.setFocus()
else:
cur_path = os.getcwd()
filename = cur_path + '/etc/passwd.txt'
fi = open(filename, 'r+')
str = name + ':' + passwd + ':' + group + '\n'
print('成功增加用户' + str + '\n')
fi.seek(0, 2)
fi.write(str)
fi.close()
else:
QMessageBox.warning(self,
"警告",
"用户已存在",
QMessageBox.Yes)
self.lineEdit.setFocus()
+

查询已有用户的实现

+

从passwd.txt中逐行读出

+
+

login

+
1
2
3
4
5
6
7
8
9
10
11
12
def readuser(self):
print('readuser')
cur_path = os.getcwd()
filename = cur_path + '/etc/passwd.txt'
fo = open(filename)
arrayofLines = fo.readlines()
names = ''
for line in arrayofLines:
line = line.strip()
listFromLine = line.split(':')
names = names + listFromLine[0] + '\n'
self.textEdit.setPlaceholderText(names)
+

删除用户的实现

+

从passwd.txt中逐行读出用户名,并与待删除用户比较,如果相同,则删除该行

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def rmuser(self):
print(1)
cur_path = os.getcwd()
filename = cur_path + '/etc/passwd.txt'
rmName = self.lineEdit.text()
with open(filename, 'r',encoding="utf-8") as r:
lines = r.readlines()
lenl = len(lines)
with open(filename, 'w',encoding="utf-8") as w:
for line in lines:
l = line.strip()
listFromLine = l.split(':')
if rmName == listFromLine[0]:
print('删除用户' + rmName)
continue
if line == '\n':
print('find换行')
line = ''
w.write(line)
+
+

3. 普通用户功能实现

普通用户可以完成对合法权限文件的读取、增加内容(上写下读)以及创建文件的操作

+

login

+

读取文件内容

+

双击文件名
获取选中文件和当前用户的完整性级别
如果用户的级别低于文件,则读取文件内容

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def readfile(self):
dict = self.getGrade()
fgrade = str(dict[self.file_path])
ugrade = self.lineEdit_2.text()
if ugrade >= fgrade:
print(ugrade+ ' 正在读取 '+fgrade)
filename = self.file_path
print(filename)
fr = open(filename)
lines = ''
arrayofLines = fr.readlines()
for line in arrayofLines:
lines += line
self.textEdit.setText(lines)
print('读取成功\n')
else:
QMessageBox.warning(self,
"警告",
"您的用户等级太高",
QMessageBox.Yes)
self.lineEdit.setFocus()
+

增加文件内容

+

双击文件名
获取选中文件和当前用户的完整性级别
如果用户的级别高于文件,则写入文件内容

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def writefile(self):
dict = self.getGrade()
fgrade = dict[self.file_path]
ugrade = self.lineEdit_2.text()
print(ugrade + ' 正在写入 ' + fgrade)
if ugrade <= fgrade:
filename = self.file_path
str = self.textEdit.toPlainText()
print(str)
fo = open(filename, 'r+')
fo.seek(0, 2)
fo.write(str)
else:
QMessageBox.warning(self,
"警告",
"您的用户等级太低",
QMessageBox.Yes)
self.lineEdit.setFocus()
+

创建文件

+

获取当前用户名和输入的文件名
在当前路径下创建名为用户名的文件
并对新创建的文件与用户等级建立字典,新文件路径为key,用户等级为value
这个字典方便读写时判断等级高低

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def touchfile(self):
urName = self.lineEdit.text()
filename = self.lineEdit_4.text()
cur_path = os.getcwd()
new_path = os.path.join(cur_path + '/file', urName)
print(urName)
if os.path.exists(new_path) == False:
os.mkdir(new_path)
os.chdir(new_path)
fr = open(filename, 'w')
key = (new_path + '/' + filename).replace('\\', '/')
fr.close()
os.chdir(cur_path)
fa = open('./etc/ac.txt', 'r')
a = fa.read()
if a == '':
dict = {}
else:
dict = eval(a)
dict[key] = self.lineEdit_2.text()
fr = open('./etc/ac.txt', 'w')
fr.write(str(dict))
fr.close()
fa.close()
+
+

五、心得体会:

六、改进部分:

+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2019/03/16/hello-world/index.html b/2019/03/16/hello-world/index.html index e69de29b..8f4ca4e8 100644 --- a/2019/03/16/hello-world/index.html +++ b/2019/03/16/hello-world/index.html @@ -0,0 +1,713 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hello World | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Hello World

+ + + +
+ + + + + +
+ + + + + +

你好!我是混元霹雳手

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2019/03/16/qq数据库的加密解密/index.html b/2019/03/16/qq数据库的加密解密/index.html index e69de29b..27eeea58 100644 --- a/2019/03/16/qq数据库的加密解密/index.html +++ b/2019/03/16/qq数据库的加密解密/index.html @@ -0,0 +1,750 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + qq数据库的加密与解密 | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

qq数据库的加密与解密

+ + + +
+ + + + + +
+ + + + + +

qq数据库采用简单加密——异或加密

数据获取:

DENGTA_META.xml—IMEI:867179032952446
databases/2685371834.db——数据库文件

+

解密方式:

明文msg_t 密文msg_Data key:IMEI
msg_t = msg_Data[i]^IMEI[i%15]

+

实验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sqlite3

IMEI = '867179032952446'
conn = sqlite3.connect('2685371834.db')
c = conn.cursor()

def _decrypt(foo):
substr = ''
#print(len(foo))
for i in range(0,len(foo)):
substr += chr(ord(foo[i]) ^ ord(IMEI[i%15]))
return substr

#rem = c.execute("SELECT uin, remark, name FROM Friends")
Msg = c.execute("SELECT msgData, senderuin, time FROM mr_friend_0FC9764CD248C8100C82A089152FB98B_New")

for msg in Msg:
uid = _decrypt(msg[1])
print("\n"+uid+":")
try:
msgData = _decrypt(msg[0]).decode('utf-8')
print(msgData)
except:
pass

+

结果

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2019/03/16/wwifi半双工侧信道攻击学习笔记/index.html b/2019/03/16/wwifi半双工侧信道攻击学习笔记/index.html index e69de29b..c15a162c 100644 --- a/2019/03/16/wwifi半双工侧信道攻击学习笔记/index.html +++ b/2019/03/16/wwifi半双工侧信道攻击学习笔记/index.html @@ -0,0 +1,906 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wifi半双工侧信道攻击学习笔记 | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

wifi半双工侧信道攻击学习笔记

+ + + +
+ + + + + +
+ + + + + +

TCP侧信道分析及利用的学习报告

背景知识

测信道

香农信息论

+

信息熵

+

什么是信息? 用来减少随机不确定的东西

+

什么是加密? 类似于加噪声,增加随机不确定性

+
+

“从密码分析者来看,一个保密系统几乎就是一个通信系统。待传的消息是统计事件,加密所用的密钥按概率选出,加密结果为密报,这是分析者可以利用的,类似于受扰信号。”

+
+

侧信道随之出现 越过加密算法增加的随机不定性,从其他的渠道获取数据标签,确定信息内容。

+
    +
  1. 早期:采集加密电子设备在运行过程中的时间消耗、功率消耗或者电磁辐射消耗等边缘信息的差异性
  2. +
  3. 而随着研究的深入,逐渐从加密设备延伸到计算机内部CPU、内存等之间的信息传递
  4. +
  5. 并在Web应用交互信息传递越来越频繁时,延伸到了网络加密数据流的破解方面
  6. +
+

侧信道攻击的流程 第一个就是侧信道泄露的截取,第二个是信息的恢复。

+
+

网络攻击

    +
  1. 中间人攻击
    +

    “指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。”

    +
    +
  2. +
+

+
    +
  • 公共wifi、路由器劫持
  • +
  • 一般使用加密来防御
  • +
  • 加密的代价:维护密钥证书、影响功能(运营商无法做缓存)
  • +
+
    +
  1. 非中间人攻击/偏离路径攻击/off-path attack
    +

    通信线路之外,攻击者看不到双方的消息,没办法截获和发送通信包。智能伪造成一方给另一方发消息。

    +
    +
  2. +
+
    +
  • 攻击成功需要:消息合法+最先到达
  • +
  • 防御措施:challenge-response/询问-应答机制
    双方在通信前交换一个随机数,这个随机数在每次的通信中都要被附带,而中间人看不见这个随机数,因此伪造的消息被认为不合法。
  • +
  • 攻击者如何得到这个随机数:侧信道
  • +
+
+

TCP三次握手

+
+
    +
  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三路握手的一部分。客户端把这段连接的序号设定为随机数A
  2. +
  3. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为A+1,SYN/ACK包本身又有一个随机产生的序号B
  4. +
  5. 最后,客户端再发送一个ACK。当服务端收到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包的序号被设定为收到的确认号A+1,而响应号则为B+1。
  6. +
+
+

通过三次握手,确定对方不是非中间人

+

TCP序列号的问题

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
19851995200120042007201220122016
MorrisMitnikZalewskyWastonkLMHerzberg作者作者
初始序列可预测真实利用漏洞仍在BGP DoSWindows攻击Puppet-assistedMalware-assistedoff-path attack
+
    +
  1. 90年代时发现并不随机:1995年伪造客户端连接微软大楼的服务器
  2. +
  3. 2007年在windows场景下用IDID侧信道猜出序列号:只针对Windows,花费几小时
  4. +
+
+

Malware-assisted

攻击模型:
给受害者安装一个无特权的应用程序(仅能网络连接),这个程序跟非中间人的攻击者里应外合,劫持手机上所有的TCP连接。

+

如何劫持TCP

+
    +
  1. 需要的信息:Facebook的连接IP地址和端口号,由此可以知道TCP连接的序列号,利用序列号伪装成Facebook给手机发消息。
    使用netstat命令获取:

    +
  2. +
  3. 任务:由于TCP的序列号通常连续,所以要精确猜到它的下一个序列号。

    +
  4. +
  5. 如何验证序列号正确:通过某种侧信道,这个恶意软件在后台可以提供反馈。
  6. +
+

变种一:防火墙

攻击过程: TCP三次握手之后产生A和B,将来传输的包序列号必须跟A和B很接近,否则,防火墙会丢弃这个包。因此只有猜对了序列号,包才能到达手机端。到达手机端后,后台的恶意软件可以帮助我们判断手机是否接受了这个数据包。

+

具体侧信道方案: CPU资源使用率(噪音很大)——>TCP计数器(后台软件运行制造噪音)——>低噪音计数器:包被丢掉时,一个相应的错误计数器。

+

解决方法: 关闭防火墙检查序列号的功能

+

变种二:无防火墙

具体侧信道方案:跟TCP业务逻辑有关的计数器——收到的TCP包序列号小于期望时增加,大于时不变。二分查找搜索正确的序列号。
影响范围:Android、Linux、MacOS、FreeBSD

+
+

Pure off-path:无恶意软件协助

+

不植入恶意软件,劫持任意两台机器的TCP连接:首先确定是否建立TCP连接,然后推测其序列号A和B。

+
+

Global Rate Limit

+

USENIX 2016 : Off-Path TCP Exploits: Global Rate Limit Considered Dangerous

+
+

侧信道: 所有的侧信道,本质上就是攻击者和受害者之间共享着某些资源,如之前的全局TCP计数器。这里使用的侧信道是 服务器上 的共享资源,限速器(RFC 5961)限制某一种包的发送速率(默认100p/s)

+

如何利用共享限速器:
先判断是否建立了连接。然后伪造TCP包,需要猜测源端口,如果猜测正确,服务器会返回一个challenge,攻击者不断触发,一共可以收到99个(还有一个发给了客户端);如果猜测错误,则一共可以收到100个challenge。

+

+

+

评估: 是否建立了连接:<10s ; Seq:30s ; ACK:<10s

+

解决方案: 1. 加噪音,100变成150、200;2. 限速器做成局部的

+
+

Unfixable WiFi timing

+

USENIX 2018 : Off-Path TCP Exploit: How Wireless Routers
Can Jeopardize Your Secrets
之前的漏洞无论是计数器还是限速器都属于软件,很好更正,但这篇文章的漏洞利用无法修复。

+
+

TCP收包的原理: 通常TCP收包要看这个包是否匹配了当前的某一个连接。如果连接匹配上了,就会去看这个包的序列号;如果序列号不对,会触发一个回复,说明这个序列号存在问题;如果序列号正确,但反向序列号不对,也会丢包。当连接匹配、序列号和反向序列号正确时,就会返回一个数据包。

+

侧信道: 攻击者伪装成服务器给客户端发包,正确的序列号会有回复,错误则没有。但回复时发送给服务器的,有没有回复攻击者并不知道。那么如何去判断有没有回复,利用无线网络的 半双工 传输。
让有回包和没有回包的时间差异放大。

+

判断流程: 客户端和路由器之间wifi通信。攻击者依次发送三个数据包,第一个包用来测试正常的RTT。第2个包是伪装成服务器发送的,如果第2个包猜对了,客户端会向服务器返回数据包,这会导致占用更长时间的wifi信道,从而会使第3个包的RTT更长。

+

+

评估: 在本地环境下,如果发送40个包,就有20ms的RTT差别。

+

攻击应用:
1. 攻击模型: 受害者访问了我们的钓鱼网站,这时javascript(傀儡)会在后台执行,主动建立到攻击者的连接(规避NAT或防火墙造成的不可抵达问题),这时攻击者就可以从外网测试RTT。

+
+

与理想情况的不同:客户端通常在NAT或防火墙之后;操作系统不一定严格遵守TCP收包的原则

+
+
Attacker -------wire----------|
+                           Router ---------wireless-------Victim (client)
+Server   -------wire----------|
+

2. 攻击目标: 推断出客户端和服务器是否建立了连接;合计连接中交换的字节数或强制中断连接;注入恶意payload到连接(不失一般性的关注web缓存投毒)。前两个不需要傀儡初始化连接,第三个不一定需要,但攻击者控制了时序,能够简化攻击。

+

3. 攻击过程: 假设傀儡已经建立了连接,攻击者可以劫持并替换任何不加密的网站(如武汉大学),并在浏览器缓存。这是因为当浏览器请求相同的ip地址时,会复用之前的TCP连接。这意味着恶意网站中的傀儡可以通过重复HTML元素来建立到目标域名的单个持久连接。然后,路径外攻击者可以进行侧信道攻击,以推断目标连接中使用的端口号和序列号,然后注入虚假的http响应,并要求浏览器不重新检查对象的新鲜度,从而达到持续性的缓存投毒。

+

4. 细节:

+
    +
  • 连接(四元组)推断: 每一轮使用30个重复包测试一个端口,如果端口号正确,就会发现RTT大幅增加。如果还要完成 web缓存投毒 ,还需要傀儡初始化连接来协助,根据系统不同,有不同的端口选择算法可以优化:windows&macOS 使用全局和顺序端口分配策略为其TCP连接选择短暂的端口号,这意味着攻击者可以在观察到与恶意Web服务器的初始连接后推断出要使用的下一个端口号,这完全消除了对端口号推断的需要。NAT 端口保留,不需要关心外部端口被转换成不可预知的内部端口。来自同一域名的多个IP地址,这意味着攻击者需要付出更大的代价来推断端口号。
  • +
  • 序列号推断: 通过利用时序侧信道来判断是否存在相应的响应,从而将窗口序列号与窗外序列号区分开来。一旦我们得到一个 窗口内序列号,通过进行二分搜索进一步将序列号空间缩小到单个值 RCV.NXT。如果还要使用傀儡建立的连接发起web缓存投毒,可以进一步优化:增大接收窗口的大小,可以减少猜测的迭代次数,通常可以放大到500000(之前是65535),而且根据RFC793,窗口放大之后就永远不会缩小。
  • +
  • TCP劫持: 通过劫持傀儡初始化的连接,可以简化web缓存投毒的过程。三个os在ACK验证上都不符合规范,所以各自处理情况也不同——windows:客户端必须持续发送请求以防止ACK接收窗口仅为一个字节,这要求攻击者必须能准确预期下一个序列号并解决大量流量带来的噪声。
    因此,作者设计了一种新策略,该策略利用处理重叠数据的TCP行为和处理损坏的HTTP响应的浏览器行为——在Windows主机上缓冲的攻击者注入数据可能会破坏来自服务器的真实HTTP响应。 (1)注入,傀儡不断从服务器上请求脚本,而攻击者发送2^23/|wnd|个欺骗性数据包,这些包的窗口序列号与RCV.NXT加上偏移量相匹配,其中|wnd|为ack接收窗口大小,第i个数据包的ACK号为i*|wnd|,payload为

    +
    1
    websocket.send(|wnd|*i)
    +

    因此,这些数据包中包含有效ACK号的一个包将被缓冲,并破坏真实的HTTP响应头。浏览器执行注入的脚本时,它将通过websocket发送猜测的ACK号,提供有效的窗口内ACK号。

    (2)利用,由于客户端已经接受了额外的欺骗payload,推进了其预期的序列号,因此客户端和服务器实际上已经被去同步。攻击者现在可以简单地发送欺骗性响应(知道预期的序列号和有效的ACK号)。如果我们只想执行一次性注入,只需用恶意脚本替换第一步中的payload就足够了。
    此外,针对Windows的注入步骤存在更加通用的替代策略,不依赖于浏览器行为。 具体来说,由于HTTP响应的前几个字节是可预先确定的(即HTTP),不破坏真实的响应,而是覆盖标题和正文以形成合法但恶意的响应。 在这种情况下,浏览器将完全忘记注入的存在。 这表明一旦序列号泄露,就存在各种方法来有效地将数据注入浏览器,而不用进行基于时间信道的慢得多的ACK号推断。

    +
  • +
+
+

Discussion

时序侧信道来自无线网络的半双工性质。由于无线协议中固有的冲突和回退,它被进一步放大。正如我们的测试路由器所证实的那样,现代无线路由器都支持CSMA / CA和RTS / CTS,因为它是802.11标准的一部分,并且该原则不太可能很快改变。
虽然作者只讨论威胁模型,其中来自受害客户端的连接是针对性的,但攻击实际上也适用于源自通过同一无线路由器连接的其他客户端的连接。这是因为所有这些客户端(例如,在相同NAT之后)共享了相同的冲突域并因此遭受相同的定时信道。通过探测数据包在任何客户端上触发的响应将有效地延迟探测后查询。在这种情况下,受害者连接(通过傀儡打开)只是为远程攻击者提供了测量碰撞的机会。
此外,我们可以扩展威胁模型以考虑无线连接的服务器,例如物联网设备。已经证明,通过公共IP地址和开放端口可以访问数百万个物联网设备。在这种情况下,可以针对此类IoT设备上的连接启动完全偏离路径的攻击。例如,计算在连接上交换的字节,终止与另一主机的连接,在正在进行的telnet连接上注入恶意命令。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2019/03/16/小米固件工具mkxqimage/index.html b/2019/03/16/小米固件工具mkxqimage/index.html index e69de29b..30529f88 100644 --- a/2019/03/16/小米固件工具mkxqimage/index.html +++ b/2019/03/16/小米固件工具mkxqimage/index.html @@ -0,0 +1,761 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 小米固件工具mkxqimage | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

小米固件工具mkxqimage

+ + + +
+ + + + + +
+ + + + + +

小米固件工具mkxqimage

小米自己改了个打包解包固件的工具,基于 trx 改的(本质上还是 trx 格式),加了 RSA 验证和解包功能,路由系统里自带:

1
2
3
4
Usage:
mkxqimg [-o outfile] [-p private_key] [-f file] [-f file [-f file [-f file ]]]
[-x file]
[-I]

+

固件解包

固件工具mkxqimage完成对固件的解包,在解包前先检查Checksum是否正确,然后利用RSA公钥/usr/share/xiaoqiang/public.pem检查RSA签名,这两个步骤通过后,根据[0x0C]的固件类型,以及[0x10]、[0x14]、[0x18]和[0x1C]的4个偏移量拆分固件。

+

固件打包

小米官方在打包固件时用RSA私钥计算出固件的RSA签名,小米路由器下载固件后用RSA公钥来验证RSA签名,有效地防止固件被篡改。

+

固件格式

路由固件的格式,基本是基于 openwrt 的 trx 这个简单的二进制文件格式

1
2
3
48 44 52 30 63 D4 11 03 FE 3D 1A FD 05 00 02 00
20 00 00 00 20 00 FE 00 00 00 00 00 00 00 00 00
FF 04 00 EA 14 F0 9F E5 14 F0 9F E5 14 F0 9F E5

+

第1~4字节:ASCII字符串“HDR0”,作为固件的标识;
第5~8字节:4字节整型数0x0311D464,表示固件的大小:51500132字节;
第9~12字节:固件的检查和;
第13~14字节:0x0005,表示固件中包含哪些部分;
第15~16字节:0x0002,表示固件格式版本号;
第17~20字节:0x00000020,表示固件第一部分在整个固件中的偏移量,0.4.85固件的第一部分是brcm4709_nor.bin,也就是Flash中除0xfe0000-0xff0000的board_data外的全镜像;
第21~24字节:0x00FE0020,表示固件第二部分在整个固件中的偏移量,0.4.85固件的第二部分是root.ext4.lzma,也就是硬盘中128M固件的压缩包;
第33字节开始是固件的正式内容开始。

+

小米开启ssh工具包

使用mkxqimage解包
(现在会提示秘钥不存在)

1
2
error fopen public key
Image verify failed, not formal image

+

如果能解包应该可以得到脚本文件upsetting.sh

+
1
2
3
4
#!/bin/sh
nvram set ssh_en=1
nvram set flag_init_root_pwd=1
nvram commit
+

执行脚本文件upsetting.sh后,将ssh_en设置为1,同时设置了flag_init_root_pwd项。当正式启动时,/usr/sbin/boot_check脚本检测到flag_init_root_pwd=1时,自动修改root用户密码,具体脚本为:

1
2
3
4
5
6
7
flg_init_pwd=`nvram get flag_init_root_pwd`
if [ "$flg_init_pwd" = "1" ]; then
init_pwd=`mkxqimage -I`
(echo $init_pwd; sleep 1; echo $init_pwd) | passwd root
nvram unset flag_init_root_pwd
nvram commit
fi

+

初始密码是mkxqimage -I的结果,实际是根据路由器的序列号计算得到。路由器的序列号印在底盖上,12位数字,如:561000088888

+

初始密码计算算法为:

+

substr(md5(SN+"A2E371B0-B34B-48A5-8C40-A7133F3B5D88"), 0, 8)

+

A2E371B0-B34B-48A5-8C40-A7133F3B5D88 为分析mkxqimage得到的salt

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2019/03/index.html b/archives/2019/03/index.html index e69de29b..678f22e3 100644 --- a/archives/2019/03/index.html +++ b/archives/2019/03/index.html @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 混元霹雳手 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2019/index.html b/archives/2019/index.html index e69de29b..8958df47 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 混元霹雳手 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/index.html b/archives/index.html index e69de29b..9cc1fb72 100644 --- a/archives/index.html +++ b/archives/index.html @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 混元霹雳手 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/index.html b/categories/index.html index e69de29b..96e099ce 100644 --- a/categories/index.html +++ b/categories/index.html @@ -0,0 +1,602 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + categories | 混元霹雳手 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + +
+
+ +

categories

+ + + +
+ + + + +
+ + +
+
+ 暂无分类 +
+
+ +
+
+ +
+ + + +
+ + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/css/fonts/FontAwesome.otf b/css/fonts/FontAwesome.otf deleted file mode 100644 index 8b0f54e47e1d356dcf1496942a50e228e0f1ee14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62856 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