20220712~0714 TIL

GunDDak·2022년 7월 14일
0

Today I Learned

  1. 선배님께서 주신 프로그래머스 필수 문제 2개 해결

    1) 숫자 문자열

    def solution(s):
    dict = {'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'eight': 8,
            'nine': 9}
    
    for key, value in dict.items():
        if key in s:
            s = s.replace(key, str(value))
    
    answer = int(s)
    return answer

    이 문제는 replace만 쓰면 됐기에 그리 어려운 문제는 아니었다.
    한번 막혔던 것은 replace함수도 결국 함수이기에 이걸 받을 곳이 필요했다는 것이다.
    처음에 s.replace(key, str(value))만 해서 찍어보니 막상 값이 바뀌지 않았던 이슈이다.

    2) 키패드 누르기

    def distance(current, selection):
    if selection == 0:
        selection = 11
    if current == 0:
        current = 11
    dist = 0
    if current % 3 == 0:  # 오른쪽
        current -= 1
        dist += 1 + abs((selection - current)) / 3
    elif current % 3 == 1:  # 왼쪽
        current += 1
        dist += 1 + abs((selection - current)) / 3
    elif current % 3 == 2:  # 중간
        dist += abs((selection - current)) / 3
    
    return dist
    
    def solution(numbers, hand):
    cur_left = 10
    cur_right = 12
    answer = ''
    for i in numbers:
        if i == 1 or i == 4 or i == 7:
            cur_left = i
            answer += 'L'
        elif i == 3 or i == 6 or i == 9:
            cur_right = i
            answer += 'R'
        else:
            left_dist = distance(cur_left, i)
            right_dist = distance(cur_right, i)
            if left_dist > right_dist:
                cur_right = i
                answer += 'R'
            elif left_dist < right_dist:
                cur_left = i
                answer += 'L'
            else:
                if hand == 'left':
                    cur_left = i
                    answer += 'L'
                else:
                    cur_right = i
                    answer += 'R'
    return answer

    두 번째 문제는 처음에 어떻게 접근해야할지 감 조차도 안 왔다.
    왼쪽의 147과 오른쪽의 369는 괜찮았는데 중간에 있는 2580을 눌렀을 때 손가락의 현재 위치와 목표 버튼의 거리를 구하는 것이 관건이었다. 그래서 123456789*0#이 있는데 별에 10을 주고 0에 11을 주고 샾에 12를 주고 같은 줄에서 인접하고 있는 두개의 버튼의 숫자 차이는 무조건 3일수 밖에 없는 규칙을 이용해서 해결을 했다.

  2. Pwnable
    랩실세미나 준비 겸 포너블을 다시 시작했다.
    커리큘럼은 Dreamhack으로 따라갈 것이다.
    처음에 TIL로 어셈블리를 쓰기에는 포너블을 위한 최소한의 어셈블리만 알고있기에 내가 너무 아는 것이 없고 내가 알고 있는 것만 쓰기에는 너무 부실해서 바로 메모리 보호기법으로 넘어간다.

많은 시스템해킹들의 주요 공격기법은 버퍼오버플로우로부터 귀인되는 Memory Corruption에서 비롯된다.
버퍼 오버플로우는 당장 단어만 봐도 알 수 있듯이 입력을 받을 때 해당 데이터의 크기를 지정하지 않거나 검사하지 않으면 그 아래에 있는 영역까지 침범을 하여 내용을 바꾸는 것을 의미한다.

보통 이런 버퍼같은 것 밑에 해당 함수를 불러왔던 ebp를 저장할 SFP와 해당 함수가 끝나고 이를 호출했던 함수로 돌아가는 Return Address가 있는데 만약에 공격자가 이 Return Address에 접근하여 이를 바꿀 수 있다면 공격자가 원하는 함수나 쉘 코드를 실행시킬 수 있을 것이다.

그래서 이러한 메모리를 보호하는 여러가지 기법들이 나오는데 그 첫 번째가 Canary이다.
Canary는 프로세스가 실행이 되면 운영체제 자체적으로 랜덤값을 만들고 이를 버퍼와 SFP사이에 복사되는 값이다. 그리고 해당 함수가 끝날 때 이 랜덤값과 Canary를 비교하여 다르면 그냥 끝내버린다. 사실상 Canary 밑으로의 데이터의 무결성을 입증을 해주는 것이다.

이렇게 SFP와 버퍼사이에 Canary를 넣어 위에 말한 것처럼 동작하게 한다.
이를 어셈블리로 보면

eax에 세그먼트 레지스터 gs에 할당된 랜덤값 (일반적인 방법으로는 볼수 없음)을 ebp-0x8에 넣어둔다.

그리고 함수가 끝날 때

edx에 아까 ebp-0x8에 있는 값을 가져오는 것을 볼 수 있는데 이걸 아까의 세그먼트 레지스터인 gs와 xor연산을 한다.

사실 이것도 조금 놀랐던게 일단 je는 Jump if Equal의 뜻으로 말그대로 같으면 여기로 가라 즉 비교문이 선행되어야하는 명령어로 배웠기에 당연히 최소한 cmp가 위에 있어야한다고 생각했었다.
근데 떡하니 그냥 '연산'자인 xor이 있길래 엥 xor로 머 0이 나오면 같은게 자명하고 0이 안 나오면 다르다고 말할 수 있긴한데 이걸 '비교'의 행위로 볼 수 있을까 싶어서 리버싱을 공부한 형께 여쭤보니 xor연산도 일단 무슨 플래그를 바꾼다고, '비교'로 볼 수 있다고하셔서 je위에 cmp가 100% 있어야하는게 아니라고 말씀해주셨다.

어쨌든 같으면 0x8048884(어딘지는 모르겠으나 원래 돌아가야 할 분기점이다.)로 가라 다르면 je에 걸리지 않기에 0x804887f로 가라라고 되어있는데 밑에 0x804887f에 가보면 __stack_chk_fail이 실행이 되도록 적혀있다. 이는 말그대로 Canary가 변조되어서 끝내라는 함수이기에 그냥 프로세스가 끝나버린다.

이런식으로 메모리를 보호하는 기법을 Canary라고 한다.
근데 이마저 프로그램에 취약점이 있으면 Canary가 유출될 수 있는데 이는 하고는 있는데 정립이 되지 않아 지금쓰기엔 그렇고 다음에 쓸 것이다.

To do list Tomorrow

  1. 지금 풀고 있는 문제에서 막힌 CS적인 부분 더 알아보기 (리틀엔디언)
  2. 랩실세미나 ppt완성하기
  3. 진짜 큰일난 백엔드 강의 폭풍같이 들어버리기 (로그인 회원가입 구현해야하는데 사고가 난 것 같다.)
profile
tak_e_life

0개의 댓글