pwntools icon indicating copy to clipboard operation
pwntools copied to clipboard

Add kCTF pow.py

Open justinsteven opened this issue 4 years ago • 9 comments

This adds a very thin wrapper around Google's kCTF pow.py (https://github.com/google/kctf/blob/v1/docker-images/challenge/pow.py)

This is a draft and a request for comments. It should not be merged just yet.

Demo:

[/pwd/pwntools]% python3 pwnlib/data/kctf/pow.py ask

Usage:
Solve pow: {} solve $challenge
Check pow: {} ask $difficulty
  $difficulty examples (for 1.6GHz CPU) in fast mode:
             1337:   1 sec
             31337:  30 secs
             313373: 5 mins

[/pwd/pwntools]% python3 pwnlib/data/kctf/pow.py ask 1337
[WARNING] kctf-pow using random.randrange() which is not cryptographically secure
== proof-of-work: enabled ==
please solve a pow first
You can run the solver with:
    python3 <(curl -sSL https://goo.gle/kctf-pow) solve s.AAU5.AACHSYfS7R9fjck4/AaU+qCG
===================

Solution? ^CTraceback (most recent call last):
  File "/pwd/pwntools/pwnlib/data/kctf/pow.py", line 202, in <module>
    main()
  File "/pwd/pwntools/pwnlib/data/kctf/pow.py", line 169, in main
    line = f.readline().decode("utf-8")
KeyboardInterrupt

[/pwd/pwntools]% python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pwn
>>> pwn.kctf_pow_<tab><tab>
pwn.kctf_pow_solve(   pwn.kctf_pow_verify(
>>> pwn.kctf_pow_solve("s.AAU5.AACHSYfS7R9fjck4/AaU+qCG")
[NOTICE] kctf-pow running 10x slower, gotta go fast? pip3 install gmpy2
's.AAAHmgGmZgtfk2AfN0JgnyLN5gcXdNtgt6eUSL89gadobDu0gHhJTDtS8jUJ2VGNJ/yqSB1Iu09qwX62VHe1Q1LXdUadsWekt9zj2tpG4FGoMUPsRMtQzVNTfTKglWY5D+d0ts5fhBccRu3kbljpn0pmVezFEWvdLeyZ2tRUAs7V1I260gRewCMl4Wt1zQU2ZGNZ1khpni60SU09lEARUl8h'
>>> pwn.kctf_pow_verify("s.AAU5.AACHSYfS7R9fjck4/AaU+qCG", _)
True

TODO:

  • [x] Get pow.py working under Python2 or give up trying

Questions:

  • Where should this live? Should we create a new module, say pwnlib.pow?
  • Is it appropriate to be vendoring Google's pow.py? It is Apache 2.0 and I've adhered to the requirement of "You must cause any modified files to carry prominent notices stating that You changed the files"
    • If it's not appropriate to be vendoring pow.py, please reject this PR. I can't find a PyPi package containing pow.py and don't want to make one.
    • If it's appropriate to be vendoring pow.py where should it go? I'm assuming data is a bad place for it. Should a libraries or lib directory be created and referenced in LICENSE-pwntools.txt as being a place in which third-party code lives?
    • If it's appropriate to be vendoring pow.py should some effort be made to hide it from consumers of pwn? The following behavior seems a bit unwanted to me.
% python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pwn
>>> pwn.data.<tab><tab>
pwn.data.absolute_import  pwn.data.kctf             pwn.data.path
pwn.data.elf              pwn.data.os
>>> pwn.data.kctf.pow.<tab><tab>
pwn.data.kctf.pow.CHALSIZE              pwn.data.kctf.pow.gmpy_sloth_square(
pwn.data.kctf.pow.GMP_NOTICE_ISSUED     pwn.data.kctf.pow.hashlib
pwn.data.kctf.pow.HAVE_GMP              pwn.data.kctf.pow.main(
pwn.data.kctf.pow.MODULUS               pwn.data.kctf.pow.os
pwn.data.kctf.pow.SOLVER_URL            pwn.data.kctf.pow.python_sloth_root(
pwn.data.kctf.pow.VERSION               pwn.data.kctf.pow.python_sloth_square(
pwn.data.kctf.pow.base64                pwn.data.kctf.pow.random
pwn.data.kctf.pow.can_bypass(           pwn.data.kctf.pow.sloth_root(
pwn.data.kctf.pow.decode_challenge(     pwn.data.kctf.pow.sloth_square(
pwn.data.kctf.pow.decode_number(        pwn.data.kctf.pow.socket
pwn.data.kctf.pow.encode_challenge(     pwn.data.kctf.pow.solve_challenge(
pwn.data.kctf.pow.encode_number(        pwn.data.kctf.pow.sys
pwn.data.kctf.pow.get_challenge(        pwn.data.kctf.pow.usage(
pwn.data.kctf.pow.gmpy_sloth_root(      pwn.data.kctf.pow.verify_challenge(

justinsteven avatar Oct 04 '21 04:10 justinsteven

Is kctf pow on pypi? Maybe it would be better to include it from there, or to make them submit it to pypi... otherwise looks fine

Arusekk avatar Oct 04 '21 07:10 Arusekk

Is kctf pow on pypi?

I couldn't find any implementations on there, granted I didn't look too hard. I've also come to learn that the canonical pow.py is not Python 2 compatible, and so even if someone did put it on PyPi it probably wouldn't work for us.

It's still TODO for me to make the vendored kctf/pow.py Python 2 compatible.

I think pwntools should consider dropping Python 2 compatibility one day soon, but that's another matter... I see it was most recently discussed on #1741.

  • What do you think of the use of data for holding kctf/pow.py as a library? Is data an ok place for it? (constants seemed like an even worse place)
  • Do you think misc is an OK place for this, or should we create a pow module to also hold things like #1318 (if it gets reopened one day)

Edited to add: Just for absolute clarity, #1318's pow.py is different to kctf/pow.py. It's why I prefixed the new functions with kctf_

justinsteven avatar Oct 04 '21 07:10 justinsteven

Added wrapper around challenge generator

% python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pwn
>>> pwn.kctf_pow_<tab><tab>
pwn.kctf_pow_generate_challenge(  pwn.kctf_pow_verify(
pwn.kctf_pow_solve(
>>> pwn.kctf_pow_ ^C
KeyboardInterrupt
>>> challenge = pwn.kctf_pow_generate_challenge(1337)
[WARNING] kctf-pow using random.randrange() which is not cryptographically secure
>>> challenge
's.AAU5.AACvAidE/gWv1+w9iNc0dqv2'
>>> pwn.kctf_pow_verify(challenge, pwn.kctf_pow_solve(challenge))
[NOTICE] kctf-pow running 10x slower, gotta go fast? pip3 install gmpy2
True

justinsteven avatar Oct 04 '21 07:10 justinsteven

Used the following to connect to a host which was running the canonical pow.py under Python 3. This was done to stress test the changes made to pow.py to ensure the changes don't break compatibility.

import pwn
import six
import sys

while True:
    with pwn.remote(sys.argv[1], sys.argv[2]) as t:
        t.recvuntil(b"python3 <(curl -sSL https://goo.gle/kctf-pow) solve ")
        challenge = six.ensure_str(t.recvline())
        solution = pwn.kctf_pow_solve(challenge)
        t.sendlineafter(six.ensure_binary("Solution? "), solution)
        assert t.recvall() == six.ensure_binary("Correct\n")

Ran this stress test from a host running Python 2, a host running Python 3, and a host running Python 3 with gmpy2 installed.

justinsteven avatar Oct 05 '21 08:10 justinsteven

Ready for review. I'm happy to squash the commits if that's preferred.

justinsteven avatar Oct 07 '21 08:10 justinsteven

Is there anything I can do to get this across the line? In the meantime can this please be given the label hacktoberfest-accepted

justinsteven avatar Oct 25 '21 22:10 justinsteven

I've realised that a new module requires changes to docs/ but I'm not sure how to do that. If someone can let me know what that change should look like I'm happy to make it.

justinsteven avatar Jan 18 '22 09:01 justinsteven

@justinsteven sorry for the long silence! Are you willing to keep working on this? I could have used this a few times and was always annoyed this isn't merged yet.

I think having a pwnlib.pow module where other pow "providers" could live as well in the future would be great and having a tube.solve_pow("kctf") function to handle the pow for you. Stripping the implementation and keeping a notice at the top, that this is derived from kctf's pow.py + license should be fine for the kctf class.

peace-maker avatar Jul 07 '23 12:07 peace-maker

@peace-maker I don't have time to work on this at the moment I'm afraid, please feel free to take over if you'd like :)

justinsteven avatar Jul 10 '23 23:07 justinsteven