0.64位程序参数一次保存在RDI,RSI,RDX,RCX,R8和 R9,具体见图
1.<_libc_csu_init>有一些万能gadget,汇编如下
#!bash
00000000004005a0 <__libc_csu_init>:
4005a0: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp)
4005a5: 4c 89 64 24 e0 mov %r12,-0x20(%rsp)
4005aa: 48 8d 2d 73 08 20 00 lea 0x200873(%rip),%rbp # 600e24 <__init_array_end>
4005b1: 4c 8d 25 6c 08 20 00 lea 0x20086c(%rip),%r12 # 600e24 <__init_array_end>
4005b8: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp)
4005bd: 4c 89 74 24 f0 mov %r14,-0x10(%rsp)
4005c2: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp)
4005c7: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp)
4005cc: 48 83 ec 38 sub $0x38,%rsp
4005d0: 4c 29 e5 sub %r12,%rbp
4005d3: 41 89 fd mov %edi,%r13d
4005d6: 49 89 f6 mov %rsi,%r14
4005d9: 48 c1 fd 03 sar $0x3,%rbp
4005dd: 49 89 d7 mov %rdx,%r15
4005e0: e8 1b fe ff ff callq 400400 <_init>
4005e5: 48 85 ed test %rbp,%rbp
4005e8: 74 1c je 400606 <__libc_csu_init+0x66>
4005ea: 31 db xor %ebx,%ebx
4005ec: 0f 1f 40 00 nopl 0x0(%rax)
4005f0: 4c 89 fa mov %r15,%rdx
4005f3: 4c 89 f6 mov %r14,%rsi
4005f6: 44 89 ef mov %r13d,%edi
4005f9: 41 ff 14 dc callq *(%r12,%rbx,8)
4005fd: 48 83 c3 01 add $0x1,%rbx
400601: 48 39 eb cmp %rbp,%rbx
400604: 75 ea jne 4005f0 <__libc_csu_init+0x50>
400606: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx
40060b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400610: 4c 8b 64 24 18 mov 0x18(%rsp),%r12
400615: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13
40061a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14
40061f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15
400624: 48 83 c4 38 add $0x38,%rsp
400628: c3 retq
2.gcc的编译选项:
-z -execstack关闭NX
-z -noexecstack开启NX
-no-pie关闭PIE
-pie开启PIE
-g 参数可以用GDB加载时l,b <line>在源代码第<line>行下断点
关于canary的几个编译选项:
-fstack-protector 启用保护,不过只为局部变量中含有数组的函数插入保护
-fstack-protector-all 启用保护,为所有函数插入保护
-fstack-protector-strong 类似windows下GS的一个编译选项,以下加入canary1)在本地变量地址作为右值表达式或作为函数参数2)本地变量是数组或含数组的union
-fstack-protector-explicit 只对有明确stack_protect attribute的函数开启保护
-fno-stack-protector 禁用保护
3.readelf -S <filename>查看文件段偏移
readelf -r <filename>查看文件重定位表,.rel.dyn和.rel.plt
4.gdb-peda安装
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
5.pwndbg安装
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
6.windbg实用命令
!gflag +hpa
这条命令用于定位堆溢出点,hpa=place heap allocations at the end of pages.
sx
set exceptions。sxe ld:<moudle name>,set exceptions enable when load <moudle name>
7.objdump -d -j .plt <filename> 查看<filename>的plt表
objdump -R <filename> 查看<filename>的got表
objdump -M intel -d <filename> 可以查看<filename>bin文件的intel汇编,默认at&t
8.scp -P<port> user@computername:<path> <local_path>下载远程文件<path>到本地<local_path>
9.cat /proc/[pid]/maps 查看进程加载信息
10.
sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"
关闭系统ASLR
0:没有随机化。即关闭 ASLR。
1:保留的随机化。共享库、栈、mmap() 以及 VDSO 将被随机化。
2:完全的随机化。在 1 的基础上,通过 brk() 分配的内存空间也将被随机化。
ASLR并不负责代码段和数据段的随机化
11.gdb查找system,'/bin/sh'
print system 查找system函数地址
print __libc_start_main 查找main入口
find <addr of __libc_start_main>,+<offset>,"/bin/sh" 查找"/bin/sh"
12.关于RELRO
部分RELRO(由ld -z relro启用): 将.got段映射为只读(但.got.plt还是可以写) 重新排列各个段来减少全局变量溢出导致覆盖代码段的可能性. 完全RELRO(由ld -z relro -z now启用) 执行部分RELRO的所有操作. 让链接器在链接期间(执行程序之前)解析所有的符号, 然后去除.got的写权限. 将.got.plt合并到.got段中, 所以.got.plt将不复存在.
13.pwntools加载指定libc启动
p=process('<process_name>',env={"LD_PRELOAD":"<libc_absolute_path>"})
14.docker&angr配置安装
docker安装
angr安装:
docker pull angr/angr
15.手动下载符号表
cmd:<windbg_path>/symchk.exe <target_dll_path> /s SRV*<download_path>*http://msdl.microsoft.com/download/symbols
16.windows下利用管理员权限CMD替换系统DLL
takeown /f <dll_path>
icacls <dll_path> /grant administrators:F
17.windbg在进程启动时附加
注册表[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<app>.exe]添加字符串值debugger,value为windbg.exe
系统环境变量path添加windbg安装路径
18.nm -C <filename> 查看<filename>符号表
19.apt-get source libc6-dev 下载源码
grep "<search_target>" -r ./<libc_source_path>/ 查找<search_target>在<libc_source_path>的位置
20._IO_file
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE }; struct _IO_FILE_plus { FILE file; //FILE=_IO_FILE const struct _IO_jump_t *vtable; }; struct _IO_FILE; /* The opaque type of streams. This is the definition used elsewhere. */ typedef struct _IO_FILE FILE; struct _IO_jump_t { JUMP_FIELD(size_t, __dummy); JUMP_FIELD(size_t, __dummy2); JUMP_FIELD(_IO_finish_t, __finish); JUMP_FIELD(_IO_overflow_t, __overflow); JUMP_FIELD(_IO_underflow_t, __underflow); JUMP_FIELD(_IO_underflow_t, __uflow); JUMP_FIELD(_IO_pbackfail_t, __pbackfail); /* showmany */ JUMP_FIELD(_IO_xsputn_t, __xsputn); JUMP_FIELD(_IO_xsgetn_t, __xsgetn); JUMP_FIELD(_IO_seekoff_t, __seekoff); JUMP_FIELD(_IO_seekpos_t, __seekpos); JUMP_FIELD(_IO_setbuf_t, __setbuf); JUMP_FIELD(_IO_sync_t, __sync); JUMP_FIELD(_IO_doallocate_t, __doallocate); JUMP_FIELD(_IO_read_t, __read); JUMP_FIELD(_IO_write_t, __write); JUMP_FIELD(_IO_seek_t, __seek); JUMP_FIELD(_IO_close_t, __close); JUMP_FIELD(_IO_stat_t, __stat); JUMP_FIELD(_IO_showmanyc_t, __showmanyc); JUMP_FIELD(_IO_imbue_t, __imbue); };
关于_IO_file的利用:
p _IO_2_1_stdout_可以找到vtable的地址,然后覆盖vtable的指针即可改变程序的流程
p *(struct _IO_jump_t *)<vtable_addr>可以查看vtable的内容
21.开启PIE的程序下相对偏移断点
pwndbg的一个姿势(程序运行状态有效,在需要输入的位置CTRL+C即可)
b *$rebase(offset) offset替换为断点的相对偏移
22.ROPgadget --binary <filename> --only "pop|ret" | grep <reg>
过滤<filename>中<reg>的rop gadget
23.关于FORTIFY机制
按我个人的理解这是缓冲区溢出的缓解措施,这个机制会进行如下操作:
1)在gcc编译阶段使用编译选项-D_FORTIFY_SOURCE=2(1 或者 2),gcc会检测到使用strcpy及类似危险函数时未检查边界的情况,给出warning
2)对格式化字符串利用的限制,包括参数解析的地址不能位于可读可写区域、使用类似%2$x必须使用%1$x
3)对于需要解析地址的函数替换成对应的__*_chk函数
24.apt-get
# apt-get update——在修改/etc/apt/sources.list或者/etc/apt/preferences之後运行该命令。此外您需要定期运行这一命令以确保您的软件包列表是最新的。 # apt-get install packagename——安装一个新软件包(参见下文的aptitude) # apt-get remove packagename——卸载一个已安装的软件包(保留配置文件) # apt-get --purge remove packagename——卸载一个已安装的软件包(删除配置文件) # dpkg --force-all --purge packagename 有些软件很难卸载,而且还阻止了别的软件的应用,就可以用这个,不过有点冒险。 # apt-get autoclean apt会把已装或已卸的软件都备份在硬盘上,所以如果需要空间的话,可以让这个命令来删除你已经删掉的软件 # apt-get clean 这个命令会把安装的软件的备份也删除,不过这样不会影响软件的使用的。 # apt-get upgrade——更新所有已安装的软件包 # apt-get dist-upgrade——将系统升级到新版本 # apt-cache search string——在软件包列表中搜索字符串 # dpkg -l package-name-pattern——列出所有与模式相匹配的软件包。如果您不知道软件包的全名,您可以使用“*package-name-pattern*”。 # aptitude——详细查看已安装或可用的软件包。与apt-get类似,aptitude可以通过命令行方式调用,但仅限于某些命令——最常见的有安装和卸载命令。由于aptitude比apt-get了解更多信息,可以说它更适合用来进行安装和卸载。 # apt-cache showpkg pkgs——显示软件包信息。 # apt-cache dumpavail——打印可用软件包列表。 # apt-cache show pkgs——显示软件包记录,类似于dpkg –print-avail。 # apt-cache pkgnames——打印软件包列表中所有软件包的名称。 # dpkg -S file——这个文件属于哪个已安装软件包。 # dpkg -L package——列出软件包中的所有文件。 # apt-file search filename——查找包含特定文件的软件包(不一定是已安装的),这些文件的文件名中含有指定的字符串。apt-file是一个独立的软件包。您必须先使用apt-get install来安装它,然後运行apt-file update。如果apt-file search filename输出的内容太多,您可以尝试使用apt-file search filename | grep -w filename(只显示指定字符串作为完整的单词出现在其中的那些文件名)或者类似方法,例如:apt-file search filename | grep /bin/(只显示位于诸如/bin或/usr/bin这些文件夹中的文件,如果您要查找的是某个特定的执行文件的话,这样做是有帮助的)。 apt-get update 系统软件包更新
25.linux下使用shadowsocks代理
apt-get install shadowsocks leafpad /etc/shadowsocks.json json文件如下 { "server":"server_addr", "server_port":port, "local_address": "127.0.0.1", "local_port":local_port, "password":"passwd", "timeout":300, "method":"crypt-type", "fast_open": true, "workers": 1 } 启动代理: nohup sslocal -c /etc/shadowsocks.json &
26.本地socat部署pwn环境
socat tcp4-listen:<port>,reuseaddr,fork exec:"env LD_PRELOAD=<libc_path> <execute_file_path>" &
socat安装:
wget http://www.dest-unreach.org/socat/download/socat-1.7.3.2.tar.gz tar zxf socat-1.7.3.2.tar.gz cd socat-1.7.3.2 ./configure make make install
27.在Linux中,值为0、1、2的fd分别代表标准输入、标准输出和标准错误输出,在程序中打开文件得到的fd从3开始增长
28.Docker安装
#!/bin/bash apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D; echo 'deb https://apt.dockerproject.org/repo debian-stretch main' > /etc/apt/sources.list.d/docker.list; apt-get install apt-transport-https ca-certificates; apt-get update && sudo apt-get install docker-engine; systemctl start docker; systemctl enable docker; systemctl status docker; exit; EOF
运行以上脚本
安装docker-compose
pip install docker-compose
测试安装(需要注册docker账号)传送门
docker login
docker run hello-world
docker加速
使用阿里云docker镜像加速,获取加速地址
docker version不低于1.10时,直接修改daemon配置文件 路径:/etc/docker/daemon.json(没有则新建) 添加如下内容: { "registry-mirrors": ["<your accelerate address>"] } 重启docker即可 修改/etc/default/docker DOCKER_OPTS="<your accelerate address>" sudo tee -a /etc/default/docker& sudo service docker restart
29.记录一个shellcode编写时突破字节限制的奇技淫巧
sc=asm('xchg rdi,rsi') sc+=asm('mov dl,xx') sc+=asm('syscall')
即通过交换rdi和rsi的值,执行一次sys_read(rdi,xx),这样汇编之后的shellcode只有7字节(在除rdi外寄存器全部置零的情况下就可以发挥作用了)